It took me some effort to create a minimum example.
Some snippets first (a minimum working example follows further down):
Code: Select all
Structure CP_TYPE
dDummy1.d
dDummy2.d
EndStructure
Structure Arg_TYPE
dummy1.l
List CP.CP_TYPE()
EndStructure
w1.Arg_TYPE
w2.Arg_TYPE
For i = 1 To #Elements
AddElement(w1\CP())
AddElement(w2\CP())
Next
; this seems just fine:
; For i = 1 To #Elements
; AddElement(w1\CP())
; Next
; For i = 1 To #Elements
; AddElement(w2\CP())
; Next
ClearList(w1\CP())
the w2 list is cleared, the memory is completely freed (and vice versa).
I my original code, elements are added at various places to the w1 and w2 lists.
Of course, I don't want to clear both list to get the memory back. I do not get any errors. ClearList
does not have a return value to tell that freeing did not occur.
It seem the two lists are somehow connected in terms of memory management.
Am I doing something wrong or is this a bug? A workaround to clear just one list with freed memory is deeply appreciated.
This problem also occurs when using DeleteElement on either w1 or w2, the memory only gets freed
dependent on the other list. I expect the lists to be independent.
Minimum Example
Code: Select all
Enumeration
#PSAPI_DLL_LIB
EndEnumeration
#Elements = 2000000
Structure CP_TYPE
dDummy1.d
dDummy2.d
EndStructure
Structure Arg_TYPE
dummy1.l
List CP.CP_TYPE()
EndStructure
w1.Arg_TYPE
w2.Arg_TYPE
Prototype GetProcessMemoryInfo( hProcess, *address, size )
If Not OpenLibrary(#PSAPI_DLL_LIB, "psapi.dll")
MessageBox_(0,"Failed to open library psapi.dll","Error",#MB_OK | #MB_ICONERROR | #MB_SETFOREGROUND | #MB_TOPMOST)
End
EndIf
; Debug " psapi.dll open"
Global GetProcessMemoryInfo_.GetProcessMemoryInfo = GetFunction(#PSAPI_DLL_LIB, "GetProcessMemoryInfo")
Procedure.d GetWorkingSetSize_MB()
pmc.PROCESS_MEMORY_COUNTERS
If GetProcessMemoryInfo_(GetCurrentProcess_(), pmc, SizeOf(PROCESS_MEMORY_COUNTERS))
ProcedureReturn pmc\WorkingSetSize / (1024 * 1024)
Else
ProcedureReturn 0
EndIf
EndProcedure
If OpenConsole()
initial_size.d = GetWorkingSetSize_MB()
PrintN("Initial Size: " + StrD(initial_size,2) + " MB")
; creating the lists
; the trouble version: (this causes the memory management to be somewhat interlaced, freeing the memory becomes unreliable)
For i = 1 To #Elements
AddElement(w1\CP())
AddElement(w2\CP())
Next
; this seems just fine:
; For i = 1 To #Elements
; AddElement(w1\CP())
; Next
; For i = 1 To #Elements
; AddElement(w2\CP())
; Next
; For each element the size shall increase by
; - the size of CP_TYPE
; - 2 pointers For *next And *previous
; - some additional overhead For memory management: 4 bytes on x86 (LinkedList memory management on Team Blog) And 8 bytes on x64 measured here
; expected_element_size.l = SizeOf(CP_TYPE) + 2 * SizeOf(integer)
; PrintN("expected element size: " + Str(expected_element_size))
; consumed_bytes_per_element.l = 1024*1024*(GetWorkingSetSize_MB() - initial_size) / ( 2 * #Elements)
; PrintN("consumed bytes per element: " + Str(consumed_bytes_per_element))
; PrintN("management overhead: " + Str(consumed_bytes_per_element - expected_element_size) + " bytes per element")
PrintN("Size with " + Str(ListSize(w1\CP())) + " w1 elements and " + Str(ListSize(w2\CP())) + " w2 elements: " + StrD(GetWorkingSetSize_MB(),2) + " MB")
; clearing the w1 list
ClearList(w1\CP())
; alternatively:
; While DeleteElement(w1\CP())
; Wend
PrintN("Size with " + Str(ListSize(w1\CP())) + " w1 elements and " + Str(ListSize(w2\CP())) + " w2 elements: " + StrD(GetWorkingSetSize_MB(),2) + " MB")
; the w1 list appears to be cleared but the associated memory is not freed. Using DeleteElement isn't freeing the memory either
; now clear the w2 list
ClearList(w2\CP())
PrintN("Size with " + Str(ListSize(w1\CP())) + " w1 elements and " + Str(ListSize(w2\CP())) + " w2 elements: " + StrD(GetWorkingSetSize_MB(),2) + " MB")
; add suddenly all of the memory gets freed!
PrintN("Any key to end.")
String$ = Input()
CloseConsole()
EndIf
End