System memory leak in this code...

I now have found a system memory leak and was able to find the part in my code which is causing it.

I don’t see where it is happening and hope someone can give me a hint:

 local WeaponX,WeaponY=Weapon:localToContent( 0,0 )                         local enemyX,enemyY=lockedOnEnemy:localToContent( 0,0 )                         local damage=Weapon.damage                         local endX,endY=Weapon.laserGoalPoint2:localToContent( 0,0 )                         if laseractive==false then                             laseractive=true                             local ePosX,ePosY -- THIS IS THE PROBLEM AREA: if \_G.Enemy then                                for \_, enemyx in pairs( \_G.Enemy ) do                                    if enemyx and enemyx~=nil and enemyx.x and enemyx.x~=nil then                                                                                      ePosX,ePosY=enemyx:localToContent( 0,0 )                                             --local ePosX=enemyx.x                                             --local ePosY=enemyx.y                                             if Weapon.laser.isVisible==true and enemyx.isAttackable==true and enemyx.isVisible==true then                                                 if CircleLineCollDetection (WeaponX,WeaponY,endX,endY,ePosX,ePosY,enemyx.width\*0.5) then                                                     -- check for enemy death                                                     if Weapon.laser.isVisible==true then                                                         -- old pos: checkLaserEnemyHit(enemyx,damage,Weapon)                                                         -- checking if smoke is already on:                                                        if enemyx and enemyx.isVisible==true and enemyx.hitsmoke and enemyx.hitsmoke.state~="playing" then                                                             enemyx.hitsmoke:start()                                                        end                                                        checkLaserEnemyHit(enemyx,damage,Weapon)                                                     else                                                       laseractive=false                                                       -- checking if smoke is already on:                                                        --if enemyx.hitsmoke.state=="playing" then                                                             --enemyx.hitsmoke:stop()                                                        --end                                                        break                                                     end                                                                                                      else                                                     --enemyx.alpha=1                                                     --if enemyx.hitsmoke.state=="playing" then                                                         --enemyx.hitsmoke:stop()                                                         --print ("emitter should be stopped now")                                                    --end                                                    -- TEST:                                                     if enemyx and enemyx.isVisible and enemyx.hitsmoke and enemyx.hitsmoke.state=="playing" then                                                         enemyx.hitsmoke:stop()                                                     end                                                 end                                             end -- version 2.2 update end if laserweapon visible                                         else -- enemyx and enemyx~=nil then                                             ---if enemyx.hitsmoke.state=="playing" then                                                   ---enemyx.hitsmoke:stop()                                                   ---print ("emitter should be stopped now")                                              --end                                              if enemyx and enemyx.isVisible==true and enemyx.hitsmoke and enemyx.hitsmoke.state=="playing" then                                                 enemyx.hitsmoke:stop()                                              end                                         end                                    end                                                             end

Here is the function code for CircleLineCollDetection which is used above:

CircleLineCollDetection = function (x1,y1,x2,y2, circlex, circley, circler) &nbsp;&nbsp;&nbsp; local x,y,dist &nbsp;&nbsp;&nbsp; for n=0,1,0.001 do &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = x1 + ((x2 - x1) \* n) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y = y1 + ((y2 - y1) \* n) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- old: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --dist = sqrt((x - circlex)^2 + (y - circley)^2) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --print ("first dist= "..dist) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- new: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dist = ((x - circlex)^2 + (y - circley)^2)^0.5 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(dist \<= circler) then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return true &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- DO NOTHING &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp; end end

And the checkLaserEnemyHit function code:

local checkLaserEnemyHit = function (theenemy,newdamage,weapon) &nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp; -- \*\* removing the hp points and check for death and update text stats \*\* &nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp; local enemy=theenemy &nbsp; local enemymoney=enemy.deathmoney &nbsp; local enemyscore=enemy.scorePoints &nbsp; local hiteffect &nbsp; if enemy and enemy.resistance and enemy.resistance==2 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- do nothing because the enemy has a res for this weapon! &nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if enemy and enemy.statusbarFill and enemy.hitpoints and enemy.maxhitpoints then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.hitpoints=enemy.hitpoints-newdamage &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newscaleval=enemy.hitpoints/enemy.maxhitpoints &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if newscaleval\>0 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.statusbarFill.xScale=newscaleval &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if newscaleval\>=0.6 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.statusbarFill:setFillColor( \_G.appleDesignColor4\_R,\_G.appleDesignColor4\_G,\_G.appleDesignColor4\_B) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif newscaleval\>=0.3 and newscaleval\<0.6 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.statusbarFill:setFillColor( \_G.appleDesignColor2\_R,\_G.appleDesignColor2\_G,\_G.appleDesignColor2\_B) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elseif newscaleval\<0.3 then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.statusbarFill:setFillColor( \_G.appleDesignColor1\_R,\_G.appleDesignColor1\_G,\_G.appleDesignColor1\_B) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp; end &nbsp; &nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp; if enemy.hitpoints\<=0 and enemy.isAttackable==true and enemy.isVisible==true then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\* The Enemy is dead now&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.isVisible=false &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.isAttackable=false --.isAttackable &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.newEnemySprite:setSequence ((enemy.name.." Death")) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.newEnemySprite:play() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- stop a possible laser smoke from the enemy &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if enemy.hitsmoke then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if enemy.hitsmoke.state=="playing" then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enemy.hitsmoke:stop() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\* If this was the target Enemy for the weapon \*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\* we have to set back the target value here&nbsp;&nbsp; \*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if enemy==weapon.lockedOnEnemy then &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; weapon.lockedOnEnemy=nil &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\* Show Enemy Explosion now \*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; func.explodeEnemy(enemy) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; composer.state.money=composer.state.money+enemymoney &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; composer.state.levelscore=composer.state.levelscore+enemyscore &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; updateMoneyText (composer.state.money) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; updateScoreText (composer.state.levelscore) &nbsp; else -- means the enemy was hit but NOT destroyed yet &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\* looking up the type of weapon first \*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -- not used! &nbsp; end

You have two variables: enemyX and enemyx in your code. Are they supposed to be the same, i.e. did you make a typo, or do you just have two almost identical variable names? If it isn’t a mistake, consider making the variable names a bit more unique in the future. :stuck_out_tongue:

As for the memory leaks, I like to say that trying to identify and fix memory leaks is a fine art. The only way I even agree to do it is by being able to work on the project/code, so that I can set up checks where necessary and actually run the code. I can’t spot memory leaks by just looking at code like you’ve provided with any degree of certainty. Someone else may be able to help you out better.

What I’d recommend is that you isolate that part that you’ve found out to be your problem area. Then keep testing it separately until you find out which specific element is causing the leak.

yes, the enemyX and enemyx are different ones and I didn’t notice because I just have changed the object table.

Thanks for your help. I will work through this part and check all the included functions to find it.

If you can’t track it down by looking at your code, I’d consider running a memory profiler.  

https://github.com/search?utf8=%E2%9C%93&q=lua+memory+profiler&type=

There used to be one by M.Y. Developers, but the company is gone.  Does anyone know if they open-sourced it like they did AutoLan?  I still have it and it still works (imperfectly). 

@everyone,

Has anyone here recently used a decent profiler?  There are many out there, but mostly they don’t suit this environment.

If you have a favorite that works for you, please link it here.

You have two variables: enemyX and enemyx in your code. Are they supposed to be the same, i.e. did you make a typo, or do you just have two almost identical variable names? If it isn’t a mistake, consider making the variable names a bit more unique in the future. :stuck_out_tongue:

As for the memory leaks, I like to say that trying to identify and fix memory leaks is a fine art. The only way I even agree to do it is by being able to work on the project/code, so that I can set up checks where necessary and actually run the code. I can’t spot memory leaks by just looking at code like you’ve provided with any degree of certainty. Someone else may be able to help you out better.

What I’d recommend is that you isolate that part that you’ve found out to be your problem area. Then keep testing it separately until you find out which specific element is causing the leak.

yes, the enemyX and enemyx are different ones and I didn’t notice because I just have changed the object table.

Thanks for your help. I will work through this part and check all the included functions to find it.

If you can’t track it down by looking at your code, I’d consider running a memory profiler.  

https://github.com/search?utf8=%E2%9C%93&q=lua+memory+profiler&type=

There used to be one by M.Y. Developers, but the company is gone.  Does anyone know if they open-sourced it like they did AutoLan?  I still have it and it still works (imperfectly). 

@everyone,

Has anyone here recently used a decent profiler?  There are many out there, but mostly they don’t suit this environment.

If you have a favorite that works for you, please link it here.