Goombert
|
|
Posted on: March 30, 2014, 05:43:26 pm |
|
|
Location: Cappuccino, CA Joined: Jan 2013
Posts: 2993
|
I am doing some debugging on object inheritance and noticed a memory leak in Mark Overmars original FPS example, this is only 1 of 3 bugs left in this game. The memory leak does not occur if you delete the collision event of obj_monster_basic. I am posting this here so maybe Josh or TheExDeus can spot the bug. The obj_monster1 code parses out to this. http://pastie.org/8981241The obj_monster_basic code parses out to this. http://pastie.org/8981237This is the IDE_EDIT_objectfunctionality.h requested by Harri. http://pastie.org/8984313
|
|
« Last Edit: March 31, 2014, 09:21:41 pm by Robert B Colton »
|
Logged
|
I think it was Leonardo da Vinci who once said something along the lines of "If you build the robots, they will make games." or something to that effect.
|
|
|
|
Goombert
|
|
Reply #2 Posted on: March 31, 2014, 10:45:17 am |
|
|
Location: Cappuccino, CA Joined: Jan 2013
Posts: 2993
|
Yes I am implying that Harri, I already replaced the collision event code with // do nothing and the memory leak still occurs. You have to fully delete and remove the collision event for the memory leak to stop. And the memory keeps on going up, about 1mb per second on the FPS example.
|
|
|
Logged
|
I think it was Leonardo da Vinci who once said something along the lines of "If you build the robots, they will make games." or something to that effect.
|
|
|
|
Goombert
|
|
Reply #4 Posted on: March 31, 2014, 09:19:29 pm |
|
|
Location: Cappuccino, CA Joined: Jan 2013
Posts: 2993
|
obj_wall_basic obj_wall1: obj_wallbasic obj_monster_basic obj_monster1: obj_monster_basic Is the basic inheritance structure, the collision event belongs to obj_monster_basic and is checking for a collision with obj_wall_basic. I have edited the original post with the parse output of the file you have requested. The GMK can be downloaded anywhere, for instance, from here. http://games.software4me.net/rpg/dload/index.php?cid=33" GM Tutorial - First Person Shooter - Mark Overmars - 12-April-2013 1:26 pm - 2.57 MB - 56" I'd really like to get this fixed, but I've run out of ideas what could be causing it On Linux we have Valgrind which people usually praise. Also, I thought you said you use Windows? I guess you dual boot then don't you?
|
|
|
Logged
|
I think it was Leonardo da Vinci who once said something along the lines of "If you build the robots, they will make games." or something to that effect.
|
|
|
TheExDeus
|
|
Reply #5 Posted on: April 01, 2014, 12:01:42 pm |
|
|
Joined: Apr 2008
Posts: 1860
|
After about 15min of debugging I tracked the problem to collide_inst_inst() [Collision_Systems/Precise/coll_impl.cpp:295] and subsequently to enigma::iterator::iterator() [Universal_System/instance_system.cpp:82]. It seems the problem is that the iterator is not released because the function returns a pointer (enigma::object_collisions*) and it is never deleted. The problem itself I guess manifests in the fact that collide_inst_inst() is ENIGMA namespace function only used by generated collision events. In IDE_EDIT_objectfunctionality.h we have this generated for that collision event: variant enigma::OBJ_obj_monster_basic::myevent_collision_0() { if (!((instance_other = enigma::place_meeting_inst(x,y,0)))) return 0; for (enigma::iterator it = enigma::fetch_inst_iter_by_int(0); it; ++it) {int $$$internal$$$ = 0; instance_other = *it; if (enigma::place_meeting_inst(x,y,instance_other->id)) {if(enigma::glaccess(int(other))->solid && enigma::place_meeting_inst(x,y,instance_other->id)) x = xprevious, y = yprevious;
{ { x = xprevious; y = yprevious; if((abs(hspeed)>= abs(vspeed)&& not place_meeting(x + hspeed, y, obj_wall_basic))) { x += hspeed; return 0; ; } if(not place_meeting(x, y + vspeed, obj_wall_basic)) { y += vspeed; return 0; ; } if(not place_meeting(x + hspeed, y, obj_wall_basic)) { x += hspeed; return 0; ; } } } ; if (enigma::glaccess(int(other))->solid) {x += hspeed; y += vspeed; if (enigma::place_meeting_inst(x, y, $$$internal$$$)) {x = xprevious; y = yprevious;}}}}
return 0; } I think the problem here is the use of pointers to iterators. That means C++ doesn't get rid of them (they don't destruct when going out of scope) and so they are never destroyed. This line "instance_other = *it;" just keeps making more of them. I at least think that is the problem. Josh maybe has better insight as he made the system. I personally think pointers are very ISO99 and we should use smart pointers or no pointers at all. Also, I thought you said you use Windows? I guess you dual boot then don't you? I do use only Windows on my laptop and main PC. But I do use Linux when programming on RaspberryPi. edit: To see that the problem is somehow there I suggest commenting out for(){} in collide_inst_inst() function in coll_impl.cpp. Then the leak is gone. Also, there seem to be a lot more leaks in ENIGMA, like in sprite structures which are never released. I used DrMemory to find leaks. Recommend trying it from here: http://www.drmemory.org/ .
|
|
« Last Edit: April 01, 2014, 12:04:51 pm by TheExDeus »
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #6 Posted on: April 04, 2014, 11:31:48 am |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
Robert, just remove blocks from the GML until the leak no longer occurs, then post the GML that can't be removed without fixing the leak. The leak will be in the code for those GML function(s).
My guess would be that in the best case, someone used new for no reason. In the worst case, it's creating some kind of resource that ENIGMA can never garbage collect/preempt.
polygone: Don't use an if-else ladder for event_perform, and don't call the parent's event first. If needed, the child event should either be the parent event, or should call it explicitly.
switch (type | numb << 8) { // Assumes type ≤ 255 case (0 | 0 << 8): return myevent_create(); case (1 | 0 << 8): return myevent_destroy(); default: return 0; }
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Goombert
|
|
Reply #7 Posted on: April 04, 2014, 12:15:43 pm |
|
|
Location: Cappuccino, CA Joined: Jan 2013
Posts: 2993
|
Josh, I removed all GML code in the event, which is the following.
{ x = xprevious; y = yprevious; if (abs(hspeed) >= abs(vspeed) && not place_meeting(x+hspeed,y,obj_wall_basic)) { x += hspeed; exit;} if not place_meeting(x,y+vspeed,obj_wall_basic) { y += vspeed; exit;} if not place_meeting(x+hspeed,y,obj_wall_basic) { x += hspeed; exit;} } I then replaced it with the following.
// do nothing And the leak still occurs, it only goes away if you delete the event from the parent object. Read Harri's report, you'll have a better understanding.
Edit: Upon further investigating Harri's claims which I have found to be true. I discovered exactly where and when the error occurs, this was tested with the BBox system. Simply removing line 100, the following code, fixes the memory leak.
if (left1 <= right2 && left2 <= right1 && top1 <= bottom2 && top2 <= bottom1) return inst2; The question now is why this occurs with parenting and not without parenting. It could be related to the object index which is passed up to the parent in the constructor which is further passed to the object_locals base class. The current system does not allow iterating children of a parent object using the parent object index, I do not know if that is possible in GM or not.
|
|
« Last Edit: April 04, 2014, 12:45:04 pm by Robert B Colton »
|
Logged
|
I think it was Leonardo da Vinci who once said something along the lines of "If you build the robots, they will make games." or something to that effect.
|
|
|
Josh @ Dreamland
|
|
Reply #8 Posted on: April 04, 2014, 03:34:13 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
The question now is why this occurs with parenting and not without parenting. Make sure instantiating the parent enemy *does not* cause this problem, and instantiating an *empty* child enemy does. It could be related to the object index which is passed up to the parent in the constructor which is further passed to the object_locals base class.The only way that this could be at all relevant is if an iterator isn't getting destroyed properly. But the iterator system I set up relies on RAII principles, so that shouldn't be the case.
The current system does not allow iterating children of a parent object using the parent object index, I do not know if that is possible in GM or not. It absolutely does. That feature is older than your event inheritance fix. If that is no longer the case, then my guess is that you broke it when you recoded the constructors for your event inheritance. I don't see the problem from the code you've posted. I'd like the exact EDL for both events, ideally. From what I can see here, there's no difference between the two objects at all, since it's the parent's own function that is called, exactly. Valgrind could tell me the exact allocation position of the leaked objects, but I am away from my ENIGMA machine, at work. Valgrind would be infinitely more useful if we had a Graphics_Systems/None to avoid OpenGL errors from displaying in the backlog.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Goombert
|
|
Reply #9 Posted on: April 06, 2014, 11:37:11 am |
|
|
Location: Cappuccino, CA Joined: Jan 2013
Posts: 2993
|
Ok, well I changed obj_monster_basic collision event to a collision with obj_wall1 instead of obj_wall_basic, and that also stopped the memory leak. Now I went further and made a test case that shows the bug also occurs without inheritance, just with collisions between objects. By simply setting obj_monster1's sprite to <no sprite> the memory leak will also disappear, give it back it's sprite, and the memory leak comes back. As for the instantiation of obj_monster_basic, I know that is not happening because a show_message call in the create event yields nothing. And I do not see them in the room instance list either, obj_wall_basic as well. Now, I know there are 367 instances of objects that inherit obj_wall_basic, and 50 instances of objects that inherit obj_monster basic, because of the following code in the Room Create code. show_message(string(instance_number(obj_wall_basic))); show_message(string(instance_number(obj_monster_basic))); Which I also tried the following variation. show_message(string(instance_number(obj_wall_basic))); show_message(string(instance_number(obj_monster1))); Which yielded the same results. I'd like the exact EDL for both events, ideally There's only 1 event, and I have provided the code for it. obj_monster_basic has a collision event with obj_wall_basic, obj_monster1 has no collision code and automatically inherits the collision event with obj_wall_basic I have created the following minimal test cases that reproduce the bug. WARNING! Run with caution, they leak 4mb's per second for me. This is with inheritance. https://www.dropbox.com/s/moe88bjkebm6ioi/inheritanceleak.gm81This is one that has no inheritance, just a collision event between one object and another, the memory leak still occurs. https://www.dropbox.com/s/4ac5evbozjfvczq/collisionmemleak.gm81
|
|
|
Logged
|
I think it was Leonardo da Vinci who once said something along the lines of "If you build the robots, they will make games." or something to that effect.
|
|
|
|
Josh @ Dreamland
|
|
Reply #11 Posted on: April 12, 2014, 07:53:25 am |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
Narrow as small a test case as you can. That's always the rule. I can't just hope the leak occurs on my machine and trace out a likely cause throughout a whole game.
And no one cares about reachable blocks, cheesedip. Someone should probably fix the leak in the sprite loader, but that only runs once. You're better off finding an actual, repeated leak.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
|
Goombert
|
|
Reply #13 Posted on: September 26, 2014, 12:07:38 am |
|
|
Location: Cappuccino, CA Joined: Jan 2013
Posts: 2993
|
Just an update me and Josh got a patch for the instance iterator fix that stops these massive memory leaks, Mark Overmars FPS example runs now at 15.2 MB's and stays there, 5 MB's lower than a blank GM8.1 game and minimal leak if any though I am sure there is some minor leakage from other systems, just by the design of GM. https://github.com/enigma-dev/enigma-dev/pull/835
|
|
« Last Edit: September 26, 2014, 12:09:32 am by Robert B Colton »
|
Logged
|
I think it was Leonardo da Vinci who once said something along the lines of "If you build the robots, they will make games." or something to that effect.
|
|
|
lonewolff
|
|
Reply #14 Posted on: September 26, 2014, 12:24:06 am |
|
|
"Guest"
|
Hang on a sec. How can the design of GM cause a memory leak in ENIGMA? GM is guilty of a lot of things but memory leaks in a rival product is probably not one of those things
|
|
|
Logged
|
|
|
|
|