Memory and event listeners

I’ve run into memory creep issues. I have a grid which is made up of lots of class instances. I wanted to be able to turn on touch listeners for all my grid squares easily and created some functions to do that. And I didn’t want to have to keep track of whether I had added a listener in order to avoid multiple event listeners, so I thought I would start every addition of the event listener with a removal. 99 times out of 100 the removal is unnecessary, but I thought that this should make sure I don’t ever have multiple listeners attached to the same object.

But I’m flicking these squares on and off very rapidly and my memory is creeping up. And the memory creep seems to be a simple function of how many times I flick the touch event listeners off and on. See the code below for a simplified example of what I’m doing. If you increase the variable “numberOfCycles” you will see memory usage go up and up. And forcing garbage removal doesn’t seem to make any difference.

What am I doing wrong? Aside from wasteful inelegant code? Thanks for any help!

Matt

(apologies if this comes out badly formatted, it seems to be an iPad issue)

[lua]
local class = require(“30log”)

local jelly = class()

function jelly:init()

self.circle = display.newCircle( math.random(700), math.random(1000), math.random(10,20) )

end

function jelly:on()

self.circle:removeEventListener(“touch”, self)
self.circle:addEventListener(“touch”, self)

end

local jellies = {}

for i = 1, 500 do

jellies[#jellies+1] = jelly()

end

print( “Memory after creating 500 instances”, collectgarbage(“count”) )

local function turnAllOn()

for i = 1, #jellies do
jellies[i]:on()
end

end

local numberOfCycles = 100

for i = 1, numberOfCycles do

turnAllOn()

end

print( collectgarbage(“count”) )

[/lua]

Well.  I can’t read that code at all… but you are probably generating new functions each time you add a listener… you only need one like this:

local function onTouch( self, event ) ... do work here end

Now, you can easily safely add and remove these as follows:

-- Safe add if( obj.touch == nil ) then obj.touch = onTouch obj:addEventListener( "touch" ) end

-- Safe remove if( obj.touch ~= nil ) then obj:removeEventListener( "touch" ) obj.touch = nil end

Sorry about the formatting. Back at a desktop now so this should work.  I played around with your idea and I think I must have been adding new functions, but I’m not sure how.  The problem came out of how I was approaching classes, nothing to do with my surplus removeEventListener.  If you see the code below, I was effectively doing this WITHOUT the line I’ve indicated by comments, which makes all the difference.  I’m not quite sure why it’s wrong without the line - it still works, the touch definitely registers, but you get the massive memory bloat problem.

[lua]

local class = require(“30log”)

local jelly = class()

function jelly:init()

  self.circle = display.newCircle( math.random(700), math.random(1000), math.random(10,20) )

end

function jelly:on()

  if  self.circle.touch == nil then

    self.circle.touch = jelly.touch – THIS is the crucial line! Without this, touch works fine but you get memory bloat.

    self.circle:addEventListener( “touch” , self)

  end

end

function jelly:touch( event )

  

  print(self.circle.x, self.circle.y)

  

end

local jellies = {}

for i = 1, 500 do

  jellies[#jellies+1] = jelly()

end

print( “Memory after creating 500 instances”, collectgarbage(“count”) )

local function turnAllOn()

  for i = 1, #jellies do

    jellies[i]:on()

  end

end

for i = 1, 1000 do

  turnAllOn()

end

print( collectgarbage(“count”) )

[/lua]

Oh, and two little words missing from my previous post: “Thank you!”. Your suggestion didn’t quite suit how I approach classes (I’m stuck in my ways from when I learned to code using Codea), but it put me on the right track.

PPS.

I was wrong, it WAS a problem with flicking the touch listener on and off multiple times during a single cycle.  Even with your safe add / remove formulation, memory balloons if you do that multiple times quickly.

So in the end the much simpler solution was to put the touch listeners on permanently and create a state variable (self.active) to control when a particular space is “on” or “off”.

Well.  I can’t read that code at all… but you are probably generating new functions each time you add a listener… you only need one like this:

local function onTouch( self, event ) ... do work here end

Now, you can easily safely add and remove these as follows:

-- Safe add if( obj.touch == nil ) then obj.touch = onTouch obj:addEventListener( "touch" ) end

-- Safe remove if( obj.touch ~= nil ) then obj:removeEventListener( "touch" ) obj.touch = nil end

Sorry about the formatting. Back at a desktop now so this should work.  I played around with your idea and I think I must have been adding new functions, but I’m not sure how.  The problem came out of how I was approaching classes, nothing to do with my surplus removeEventListener.  If you see the code below, I was effectively doing this WITHOUT the line I’ve indicated by comments, which makes all the difference.  I’m not quite sure why it’s wrong without the line - it still works, the touch definitely registers, but you get the massive memory bloat problem.

[lua]

local class = require(“30log”)

local jelly = class()

function jelly:init()

  self.circle = display.newCircle( math.random(700), math.random(1000), math.random(10,20) )

end

function jelly:on()

  if  self.circle.touch == nil then

    self.circle.touch = jelly.touch – THIS is the crucial line! Without this, touch works fine but you get memory bloat.

    self.circle:addEventListener( “touch” , self)

  end

end

function jelly:touch( event )

  

  print(self.circle.x, self.circle.y)

  

end

local jellies = {}

for i = 1, 500 do

  jellies[#jellies+1] = jelly()

end

print( “Memory after creating 500 instances”, collectgarbage(“count”) )

local function turnAllOn()

  for i = 1, #jellies do

    jellies[i]:on()

  end

end

for i = 1, 1000 do

  turnAllOn()

end

print( collectgarbage(“count”) )

[/lua]

Oh, and two little words missing from my previous post: “Thank you!”. Your suggestion didn’t quite suit how I approach classes (I’m stuck in my ways from when I learned to code using Codea), but it put me on the right track.

PPS.

I was wrong, it WAS a problem with flicking the touch listener on and off multiple times during a single cycle.  Even with your safe add / remove formulation, memory balloons if you do that multiple times quickly.

So in the end the much simpler solution was to put the touch listeners on permanently and create a state variable (self.active) to control when a particular space is “on” or “off”.