Page 1 of 1

Freememory() in thread with debugger enabled

Posted: Thu Jan 22, 2009 9:25 pm
by cas
I had a memory leak in my code when debugging and i managed to isolate it to this:

Code: Select all

Procedure MemoryOperation(*MemoryID)
  FreeMemory(*MemoryID)
EndProcedure

For i=0 To 50000
  *MemoryID = AllocateMemory(50)
  CreateThread(@MemoryOperation(),*MemoryID)
Next
Program runs until it fills pagefile (total size ~17GB on my pc, this program fills it with 15GB, with x86 version of purebasic it fills with 2GB (x86 limit per process)) and FreeMemory() is ignored:

Image

If debugger is disabled then all is working as expected.
Any tips how to debug my program?
Is this possibly bug in pb compiler?
I'm sorry if same question is already asked :oops:
Thanks

Posted: Thu Jan 22, 2009 9:30 pm
by Kaeru Gaman
I guess the threads are created too fast.
the freeing of mem does not come to work fast enough.

if you create thousands of threads within the same timeslice, the OS cant switch to the next thread in the next slice to free the mem before it's not enough mem left...

Posted: Thu Jan 22, 2009 9:40 pm
by cas
Kaeru Gaman wrote:I guess the threads are created too fast.
the freeing of mem does not come to work fast enough.

if you create thousands of threads within the same timeslice, the OS cant switch to the next thread in the next slice to free the mem before it's not enough mem left...
If i put delay:

Code: Select all

Procedure MemoryOperation(*MemoryID)
  FreeMemory(*MemoryID)
EndProcedure

For i=0 To 50000
  Delay(1000)
  *MemoryID = AllocateMemory(50)
  Delay(1000)
  CreateThread(@MemoryOperation(),*MemoryID)
Next 
then open taskmanager and i can only watch how memory usage is increasing, but this time slower :(

Posted: Thu Jan 22, 2009 9:45 pm
by Kaeru Gaman
well.. ok. it was just a guess... :?

Posted: Fri Jan 23, 2009 1:06 pm
by Trond
I can't reproduce this. In fact I have the opposite problem! Even if I allocate 1 GB and never free it, the task manager shows no more than 7 mb! :shock: :shock:

Code: Select all

For i = 0 To 1024
  *MemoryID = AllocateMemory(1024*1024)
  If *MemoryID = 0
    CallDebugger
  EndIf
Next

CallDebugger

Re: Freememory() in thread with debugger enabled

Posted: Fri Jan 23, 2009 1:29 pm
by graves
cas wrote:

Code: Select all

Procedure MemoryOperation(*MemoryID)
  FreeMemory(*MemoryID)
EndProcedure

For i=0 To 50000
  *MemoryID = AllocateMemory(50)
  CreateThread(@MemoryOperation(),*MemoryID)
Next
Your code have a logical "lack":
1. Program allocates *MemoryID
2. Program starts the thread
3. While thread starts running, your program GOES to 1. and allocates a new *MemoryID.

Sometimes, parallel thread starts quickly, and frees *MemoryID correctly. But sometimes takes longer, and *MemoryID have a new memory direction assigned by main program... and old *MemoryID lacks.

IMHO, the main problem is CreateThread, it starts a thread and continues working, it does not wait the end of thread.

Perhaps, you can change it:

Code: Select all

Global *MemoryID.l
Procedure MemoryOperation(*MemoryID)
  FreeMemory(*MemoryID)
  *MemoryID = 0
EndProcedure

*MemoryID = 0
For i=0 To 50000
  while *MemoryID
    delay(1)
  wend
  *MemoryID = AllocateMemory(50)
  CreateThread(@MemoryOperation(),*MemoryID)
Next

Posted: Fri Jan 23, 2009 1:33 pm
by Kaeru Gaman
@graves

your argumentation has a logical lack:
when transferring a variable as argument, it is stored as parameter,
and changing the variable does not longer effect the value within the procedure.

it would be clearer to write:

Code: Select all

Procedure MemoryOperation(*ThreadMemoryID)
  FreeMemory(*ThreadMemoryID)
EndProcedure

For i=0 To 50000
  *MainMemoryID = AllocateMemory(50)
  CreateThread(@MemoryOperation(),*MainMemoryID)
Next 

Posted: Fri Jan 23, 2009 5:34 pm
by cas
@trond

taskmanages shows around 10MB but this is in main memory, pagefile has all allocated memory , wierd as my system has 4,5GB RAM free (of 7GB total) and it is not allocating in main memory(RAM) :?

Image


@graves

I have to agree with Kaeru Gaman and your code has infinite loop in While::Wend (maybe setting *MemoryID as global?).

But same thing as described in first post happens with this code:

Code: Select all

Dim test_array(5000)

Procedure MemoryOperation(*MemoryID)
  FreeMemory(*MemoryID)
EndProcedure

For i=0 To 5000
  test_array(i) = AllocateMemory(50)
  CreateThread(@MemoryOperation(),test_array(i))
Next 

Delay(10000)
No matter how long delay at the end (for waiting threads to finish), always same result with debugger enabled(pagefile grows, freememory() is ignored)

Posted: Sun Jan 25, 2009 3:57 am
by technicorn
@cas
Tested with debugger on
The problem with freeing memory doesn't happen on 32 bit windows (XP home with SP3)
So either 64 bit windows behaves different, or there's a bug in the 64 bit version of PB

@trond
Try to write something into the allocated memory and it will allocate the memory in RAM, it's just a trick that is also used on Linux,
the OS just reserves as many memory as it need to hold the first page of every memory block,
but it you write something into it, it starts to allocate new RAM pages.

You can see that when you use this prog:

Code: Select all

#MemSize = 1024*1024

CompilerIf Defined(ByteVector, #PB_Structure) = 0
Structure ByteVector
  b.b[0]
EndStructure
CompilerEndIf

Define *memPtr.ByteVector

For n = 1 To 1024
  *memPtr = AllocateMemory(#MemSize)
  If Not *memPtr
    CallDebugger
  EndIf
  For idx = 0 To 4000
    *memPtr\b[idx] = -1
  Next idx
Next n
CallDebugger
If you increase the end value of the idx loop to about 4095,
it will allocate the next page, so RAM usage goes up.
It isn't exactly 4096 (one page) when it happens, because of the internal
overhead for managing the memory block.

So it can happen that you have several programs running all together using more RAM than is available, but when all start to write something to the allocated memory, the OS says, pardon, no more memory.