Freememory() in thread with debugger enabled

Just starting out? Need help? Post your questions and find answers here.
cas
Enthusiast
Enthusiast
Posts: 597
Joined: Mon Nov 03, 2008 9:56 pm

Freememory() in thread with debugger enabled

Post 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
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post 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...
oh... and have a nice day.
cas
Enthusiast
Enthusiast
Posts: 597
Joined: Mon Nov 03, 2008 9:56 pm

Post 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 :(
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

well.. ok. it was just a guess... :?
oh... and have a nice day.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post 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
User avatar
graves
Enthusiast
Enthusiast
Posts: 160
Joined: Wed Oct 03, 2007 2:38 pm
Location: To the deal with a pepper

Re: Freememory() in thread with debugger enabled

Post 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
Last edited by graves on Sun Jan 25, 2009 9:43 am, edited 2 times in total.
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post 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 
oh... and have a nice day.
cas
Enthusiast
Enthusiast
Posts: 597
Joined: Mon Nov 03, 2008 9:56 pm

Post 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)
technicorn
Enthusiast
Enthusiast
Posts: 105
Joined: Wed Jan 18, 2006 7:40 pm
Location: Hamburg

Post 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.
Post Reply