GCcollect and the amount of memory

BlitzMax Forums/BlitzMax Programming/GCcollect and the amount of memory

Rozek(Posted 2010) [#1]
Good morning!

Is there a limit of allocated memory the internal GC can handle?

On my machine (Mac mini Intel running Mac OS X 10.4.11, BlitzMAX 1.38, MaxGUI 1.37) the following example has an astonishing memory consumption curve (as shown by "top" or the system's activity display):

SuperStrict

Import BaH.Cairo


Graphics 640,480,0

SetBlend ALPHABLEND

SetClsColor 255,255,255

local i:int = 0
repeat
  i = i+1
  if (i = 30) then
    GCcollect()
  end if

  Local cairo:TCairo = TCairo.Create(TCairoImageSurface.CreateForPixmap(256,256))

  Local normalizeMat:TCairoMatrix = TCairoMatrix.CreateScale(256.0,256.0)
  cairo.SetMatrix(normalizeMat)

  Local xc:Double = 0.5
  Local yc:Double = 0.5
  Local radius:Double = 0.4
  Local angle1:Double = 45.0 
  Local angle2:Double = 180.0         

  cairo.SetLineWidth(0.05)
  cairo.Arc(xc, yc, radius, angle1, angle2)
  cairo.Stroke()

' draw helping lines 
  cairo.SetSourceRGBA(1,0.2,0.2,0.6)
  cairo.Arc(xc, yc, 0.05, 0, 360)
  cairo.Fill()
  cairo.SetLineWidth(0.03)
  cairo.Arc(xc, yc, radius, angle1, angle1)
  cairo.LineTo(xc, yc)
  cairo.Arc(xc, yc, radius, angle2, angle2)
  cairo.LineTo(xc, yc)
  cairo.Stroke()

'cairo.selectFontFace("arial", 0, 0) ' <<<<<<<<<<<<<<<<<<

  cairo.Destroy()

  Local image:TImage = LoadImage(TCairoImageSurface(cairo.getTarget()).pixmap())

  Cls
  DrawImage image,MouseX() - 128,MouseY() - 128
  Flip

  delay(33)
Until KeyHit(key_escape)

End
The code uses Brucey's Cairo wrapper - thus, don't try it unless you also have this wrapper installed!

When compiled and invoked, memory consumption raises until it drops to its inital value (roughly), then it raises again (but higher than before) and drops to its inital value. This sequence (raising for a few seconds, then dropping) happens 3 times (25...70MB, 25...115MB, 25...270MB), but then it starts raising forever (well, until my machine gets so slow - due to swapping - that I have to kill the app)

This looks strange - does anybody have any idea what might go wrong there?


matibee(Posted 2010) [#2]
I don't have the wrapper so I've not ran the code but I've seen most of the symptoms you describe many times with repeatedly allocating images. The garbage collector seems time based so sometimes an object will take several seconds to be cleaned up. Imagine how many times Local image:TImage could be allocated in that time depending on your fps.

Your GCCollect code at the head of the loop only runs once, when i first hits 30, I assume you missed an i = 0 along side the GCCollect to make it repeat every 30 frames.

I can't understand why you're doing a TCairo.Create for every frame either. I don't know anything about Cairo but surely all initialisation (no matter what API) belongs outside the rendering loop? I don't think you're doing the garbage collector any favours.


Rozek(Posted 2010) [#3]
Matt,

oops - you are right: I missed the i = 0!

Calling GCcollect explicitly (e.g. once a second) keeps the "physical memory" low (e.g. < 55MB) - but the "virtual memory" is still increasing heavily (> 1.5GB!), causing the system to start swapping.

What might be the reason for such a big difference between physical and virtual memory?

I used the mentioned Cairo calls in order to check for a memory leak within Cairo. Meanwhile, my actual application does heavy caching of lots of Cairo structures. However, with caching I run into the problem that - quite often - nothing is shown on the screen, while - without caching - Cairo displays everything. But that's an issue to be mentioned in another forum.


matibee(Posted 2010) [#4]
Could the "nothing shown on screen" issue be down to running out of vram? On my mac (with only 32mb of vram) without careful management and explicit use of gccollect it just starts returning plain white textures (which is probably an opengl failsafe).

I'd try calling the gccollect every frame: actually nullify the image and cairo objects and then call gccollect right after the flip.

Sorry I can't help much if this is getting Cairo specific but one thing does strike me as odd and that's cairo.Destroy() being called before you cairo.getTarget(). I'm surprised that works at all, unless Destroy() is not what I think it is.


Rozek(Posted 2010) [#5]
Matt,

no - it was simply my fault: the Cairo surface was based on a "dynamic image", but I forgot to embrace the Cairo drawing code by "lockImage" and "unlockImage". Now, I always get a display, but my memory is leaking again (presumably due to Image handling).

I already tried other approaches (surface based on pixmap and draw pixmap, based on pixmap and loadimage before drawing the image) but nothing works properly.

What kind of surface are YOU using?

(I also had this problem with the "misnomer" "Cairo.destroy", but only in the beginning)


Dabhand(Posted 2010) [#6]
SuperStrict

Import BaH.Cairo


Graphics 640,480,0
Local cairo:TCairo
Local image:TImage 
SetBlend ALPHABLEND

SetClsColor 255,255,255

Repeat
  cairo:TCairo = TCairo.Create(TCairoImageSurface.CreateForPixmap(256,256))

  Local normalizeMat:TCairoMatrix = TCairoMatrix.CreateScale(256.0,256.0)
  cairo.SetMatrix(normalizeMat)

  Local xc:Double = 0.5
  Local yc:Double = 0.5
  Local radius:Double = 0.4
  Local angle1:Double = 45.0 
  Local angle2:Double = 180.0         

  cairo.SetLineWidth(0.05)
  cairo.Arc(xc, yc, radius, angle1, angle2)
  cairo.Stroke()

' draw helping lines 
  cairo.SetSourceRGBA(1,0.2,0.2,0.6)
  cairo.Arc(xc, yc, 0.05, 0, 360)
  cairo.Fill()
  cairo.SetLineWidth(0.03)
  cairo.Arc(xc, yc, radius, angle1, angle1)
  cairo.LineTo(xc, yc)
  cairo.Arc(xc, yc, radius, angle2, angle2)
  cairo.LineTo(xc, yc)
  cairo.Stroke()

'cairo.selectFontFace("arial", 0, 0) ' <<<<<<<<<<<<<<<<<<

  

  image = LoadImage(TCairoImageSurface(cairo.getTarget()).pixmap())

  Cls
  DrawImage image,MouseX() - 128,MouseY() - 128
  Flip
  cairo.Destroy()
  cairo = Null
  image = Null
  GCCollect()
  Delay(33)
Until KeyHit(key_escape)

End


Does that make a difference?

I will state that I've had issues with GCCollect in the past, due to memory leaks, which literally mangled my head until I found it was DX9 and the jpg leaks!

Brucey is the lad when it comes to the inner workings of the garbage collector, he's always popped into one of my threads about it and explained stuff! :)

Dabz


Otus(Posted 2010) [#7]
Is there a limit of allocated memory the internal GC can handle?

The GC works with very close to the full 2GB (per process limit) allowed under 32bit OSes. I've successfully programmed and run programs with 1GB+ memory use. There is of course some overhead, so actual useful memory is a bit lower than that reported by e.g. top.

You shouldn't be concerned if you see periodically rising memory use as long as it comes back down. If it doesn't, there is probably a leak somewhere, but I doubt it has much to do with the GC.

(I haven't used the Cairo module, so I can't really help with that.)