Page 2 of 4

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 1:34 am
by WilliamL
Hi Luis!

I understand the concept but not much more than that. I suppose this could be useful in examining my programs. I am guessing that I would put the include reference in my program and read the results. Ok, what do the references mean. I ran your example on my Mac (yay, it worked!) and this is what I got. What does it mean in reference to your example? (imagine the data in columns :) )

Scope Name Size Current
Main NoLeak_FONT.T_NOLEAK_FONT() O -
Main NoLeak_ALLOC.T_NOLEAK_ALLOC() 4 3
Main NoLeak_IMAGE.T_NOLEAK_IMAGE() 7 6

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 11:00 am
by gnasen
It means that there are currently 0 fonts, 4 memory blocks and 7 images used, but not released. If you inspect the lists, it will say you in which source and line they have been allocated. If you for example create a new instance of whatever and delete it after that, the numbers should not change. If they increase, you have a leak :cry:

I found a little leak (at least 20bytes every minute) in my main program with this, thanks a lot!

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 11:25 am
by Fred
just of curiosity, from where your leaks come from ?

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 12:22 pm
by gnasen
Fred wrote:just of curiosity, from where your leaks come from ?
In my case I free every object (with all stuff it allocated) in a genereal "freeing procedure". However, there was one special case where I had to do a little workaround (cause of some pointer stuff, to avoid an IMA). And in this one case I skipped an If-block (the pointer was not longer available) in which I amongst other things freed a block of memory.
There error was, that the freeing should have been outside of this If-block.

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 12:35 pm
by infratec
Hi luis,

to make life easier I added a NoLeakDebug() procedure to the include file:

Code: Select all

Procedure DebugNoLeak()
  
  Shared NoLeak_FONT(), NoLeak_ALLOC(), NoLeak_IMAGE()
  Protected i
  
  i = 0
  
  If ListSize(NoLeak_FONT())
    Debug ""
    Debug "NoLeak Font:"
    Debug ""
    ForEach NoLeak_FONT()
      i + 1
      Debug "(" + Str(i) + ") " + "File: " + NoLeak_FONT()\sFile
      Debug "(" + Str(i) + ") " + "Line: " + Str(NoLeak_FONT()\iLine)
      Debug "(" + Str(i) + ") " + "ID: " + Str(NoLeak_FONT()\iFontNum)
      Debug "(" + Str(i) + ") " + "Name: " + NoLeak_FONT()\sName
      Debug "(" + Str(i) + ") " + "Size: " + Str(NoLeak_FONT()\iYsize)
      Debug ""
    Next
    Debug "----------------------------"
  EndIf
  
  If ListSize(NoLeak_ALLOC())
    Debug ""
    Debug "NoLeak Alloc:"
    Debug ""
    ForEach NoLeak_ALLOC()
      i + 1
      Debug "(" + Str(i) + ") " + "File: " + NoLeak_ALLOC()\sFile
      Debug "(" + Str(i) + ") " + "Line: " + Str(NoLeak_ALLOC()\iLine)
      Debug "(" + Str(i) + ") " + "Address: " + Str(NoLeak_ALLOC()\iAddress)
      Debug "(" + Str(i) + ") " + "Size: " + Str(NoLeak_ALLOC()\iBytes)
      Debug ""
    Next
    Debug "----------------------------"
  EndIf
  
  If ListSize(NoLeak_IMAGE())
    Debug ""
    Debug "NoLeak Image:"
    Debug ""
    ForEach NoLeak_IMAGE()
      i + 1
      Debug "(" + Str(i) + ") " + "File: " + NoLeak_IMAGE()\sFile
      Debug "(" + Str(i) + ") " + "Line: " + Str(NoLeak_IMAGE()\iLine)
      Debug "(" + Str(i) + ") " + "ID: " + Str(NoLeak_IMAGE()\iImageNum)
      Debug "(" + Str(i) + ") " + "Width: " + Str(NoLeak_IMAGE()\iWidth)
      Debug "(" + Str(i) + ") " + "Height: " + Str(NoLeak_IMAGE()\iHeight)
      Debug "(" + Str(i) + ") " + "Depth: " + Str(NoLeak_IMAGE()\iDepth)
      Debug ""
    Next
    Debug "----------------------------"
  EndIf    
  
  If i > 0
    Debug "NoLeak found " + Str(i) + " leaks!"
  Else
    Debug "NoLeak found no leaks!"
  EndIf
  
EndProcedure
CompilerElse
  Macro DebugNoLeak()
  EndMacro
Put the procedure code directly in front of the CompilerEndif.
Instead of

Code: Select all

CallDebugger ; press F12 here to inspect the NoLeak_*() lists
You can now use

Code: Select all

DebugNoLeak()
And you can left the DebugNoLeak() in your code. :mrgreen:

Bernd

@luis
If you want you can add it to your code, than I remove the code from here.

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 2:46 pm
by luis
@WilliamL
gnasen already explained it (thanks), if you need more info just ask. Anyway if you go step by step in the example and then look at the results expanding the list contents should be all clear.

@infratec
I prefer to use the variable viewer but I put a link to your post in my first one.

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 6:30 pm
by WilliamL
@gnasen - thanks for the explanation of the program output. I'm wondering if a memory leak can lead to an IMA which I have in my first program I wrote when pb became available to the Mac (many images in Procedures)? In this program (it seems) the variable values are overwritten which leads to IMAs.

@infratec - thanks for the code addition, it works fine and is a bit easier to read. I haven't figured out the 'expanding the list contents' part yet.

Hi Luis - thanks for the program. It was my understanding that when CreateImage was used the last image (of the same value) was automatically freed so no FreeImage was needed. I'm not sure where I read that but it appears to be wrong.

I hope this isn't a case of too much knowledge in the wrong hands. :)

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 8:07 pm
by luis
WilliamL wrote: Hi Luis - thanks for the program. It was my understanding that when CreateImage was used the last image (of the same value) was automatically freed so no FreeImage was needed. I'm not sure where I read that but it appears to be wrong.
No you are right, and this code is wrong under this aspect.

According to the help:
help wrote: CreateImage(2, 640, 480) ; Create an image, the n°2
ResizeImage(2, 320, 240) ; Resize the n°2 image
CreateImage(2, 800, 800) ; Create a new image in the n°2 index, the old one is automatically free'ed
and
help wrote: The purpose of this section is to describe the behaviour, creation, and handling of objects in PureBasic. For the demonstration, we will use the Image object, but the same logic applies to all other PureBasic objects.
I never use static numbering in a real program, so I overlooked this (or better I forgot about it, not really relying on this behavior).

Indeed the include should be modified to accommodate that too, but I'm not 100% sure this automatic freeing always happen with any pb command involving pb objects.

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 8:30 pm
by WilliamL
Luis,

Thanks for finding that for me, I sure couldn't remember where I saw that and was doubting my sanity! :?

I can't understand why you would use a Procedure to create an image then free it in the same procedure? What is the use of that? In my calendar program (for printing out) I have an image for each day that has many elements (such as moon/sunrise/picture background/holiday text/etc) that are all added for each day, in a procedure, and then the images are used to draw the calendar. When another month is created the whole process is repeated with the same image numbers. Is this going to cause a memory leak? I have generally used 'IsImage' before creating a new image and freeing the old image just to be on the safe side.

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 8:39 pm
by luis
WilliamL wrote: I can't understand why you would use a Procedure to create an image then free it in the same procedure? What is the use of that?
If you create an image on the fly in a proc and in the same you save the image to disk, then maybe you don't need the image anymore so you free it.

If you are using a temp image in a proc to do some kind of processing on it and then copy the result to another image, than you can free the temp image.

Etc etc etc. millions of reasons.
WilliamL wrote: Is this going to cause a memory leak?
The PB manual says NO. It's easy to verify it, write a program creating images with the same number in a loop and check memory consumption.

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 8:52 pm
by Trond

Code: Select all

CreateImage(123, 32, 32)
CreateImage(123, 32, 32) ; no leak

Image = CreateImage(#PB_Any, 32, 32)
CreateImage(Image, 32, 32) ; leak! (gives a debugger error)

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 9:03 pm
by WilliamL
Isn't Trond's example interesting! You can create an image with #PB_Any but the value is to high to create another image with that number... (at least that was my debugger error) Well, the auto freeing of images (with fixed values) is shown to work.

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 9:10 pm
by luis
It's a warning, a BIG WARNING, but the image is created, anyway obviously the previous image created with #PB_Any is leaked.

The warning is due to:
help wrote: The static, indexed way, allows you to reference an object by a predefined numeric value. The first available index number is 0 and subsequent indexes are allocated sequentially. This means that if you use the number 0 and then the number 1000, 1001 indexes will be allocated and 999 (from 1 to 999) will be unused, which is not an efficient way to use indexed objects.

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Thu Jan 12, 2012 9:15 pm
by luis
Added (hopefully) support for the case discussed above by WilliamL, the use of numeric constants for PB objects and their automatic deallocation by PB when reusing the same number.

The updated example shows that.

Re: NoLeak - include to help you find memory leaks (UPDATED)

Posted: Sat Jan 14, 2012 7:19 pm
by skywalk
Big Thanks to luis and trond for this post. 8)
Love it when code catches human error. :wink:
Maybe this feature could be added to the purifier as a sub option?