-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory leaks (bbMemAlloc & bbMemFree) #310
Comments
Works as expected as well, seems making 2 pointers in a row confuses the GC or something. Cheers. |
I checked for the generated C code ... and replaced the content of it with the fundamentals being done "inside". Framework BRL.Blitz
Import BRL.StandardIO
Local runs:int
Repeat
'direct C-code to ease "experimenting"
'! void *p1 = bbMemAlloc(1000);
'! void *p2 = bbMemAlloc(1000);
'! bbMemFree(p1);
'! bbMemFree(p2);
For Local i:Int = 0 Until 10
GCCollect()
Next
If runs mod 100 = 0
Print GCMemAlloced()
EndIf
runs :+ 1
Until runs = 1000 output:
If you remove the second memory bbmemalloc and bbmemfree - and the printed value stays constant. also using one "non-gc-malloc" makes it constant:
using other GC-malloc variants also result in constant values:
(but I did not dig about the differences yet).
results similar to the atomic-version to increased values. |
I think I found something ... Checking aboves there it defines that /* Allocate lb bytes of pointerful, traced, but not collectible data. */
GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_uncollectable(size_t lb)
{
return GC_generic_malloc_uncollectable(lb, UNCOLLECTABLE);
} So it at the end calls GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc_uncollectable(
size_t lb, int k)
{
void *op;
size_t lb_orig = lb;
GC_ASSERT(k < MAXOBJKINDS);
if (EXTRA_BYTES != 0 && EXPECT(lb != 0, TRUE)) lb--;
/* We do not need the extra byte, since this will */
/* not be collected anyway. */
if (SMALL_OBJ(lb)) {
void **opp;
[...]
} else {
op = GC_generic_malloc_aligned(lb, k, 0 /* flags */, 0 /* align_m1 */);
if (op /* != NULL */) { /* CPPCHECK */
hdr * hhdr = HDR(op); Wait ... what... So ... I simply increased the amount of to allocate memory: from 1000 to 10000
et voila.. printed values stay low (in this case alternating):
so for small objects the GC behaviour might either be bugged - or it somehow decides to keep them for almost forever. PS: /* Max size objects supported by freelist (larger objects are */
/* allocated directly with allchblk(), by rounding to the next */
/* multiple of HBLKSIZE). */
#define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2)
#define MAXOBJBYTES ((size_t)CPP_MAXOBJBYTES) Edit: regarding "keeping them for almost forever". |
This seems to leak as well:
So it isn't related to having |
If my findings are correct then it looks like it is either an incorrect usage or inappropriate choice of bwdgc functions in NG ...or a bug in bwdgc itself. Saying this based on the direct use of their functions as written in my previous replies |
Ah I see, so it only happens when using GCCollect multiple times... I was having high memory use so I found somewhere on the internet that you can use the collect function of BDWGC multiple times to clear as much memory as possible. But still... it shouldn't bug out like that I guess. |
regarding calling Why does it then not increase if you do:
instead of
... if it is connected to collecting memory then this indicates a This aside. Framework BRL.Blitz
Import BRL.StandardIO
Local runs:int
Repeat
'direct C-code to ease "experimenting"
'! void *p1 = bbMemAlloc(1000);
'! void *p2 = bbMemAlloc(1000);
'! bbMemFree(p1);
'! bbMemFree(p2);
For Local i:Int = 0 Until 10
GCCollectALittle()
Next
If runs mod 100 = 0
Print GCMemAlloced()
EndIf
runs :+ 1
Until runs = 1000 I assume this happens because
Results in a lot of prints ... I tried the opposite (printing when it has done something ) - and this line is not printed at all, so during the loops GCCollectALittle() always returns 0 / seems to decide to not do anything. Maybe the GC thinks it is not worth to "clean up" albeit it should do somewhen? So ... I increased the "Until runs =" part to 10000 - with GCCollectALittle() this is still blazing fast (while the GCCollect() starts to ... stutter and becomes slower and slower). We should call Framework BRL.Blitz
Import BRL.StandardIO
'disable auto-gc-ing!
GCSetMode(2)
Local runs:int
Repeat
'direct C-code to ease "experimenting"
'! void *p1 = bbMemAlloc(1000);
'! void *p2 = bbMemAlloc(1000);
'! bbMemFree(p1);
'! bbMemFree(p2);
For Local i:Int = 0 Until 10
If GCCollectALittle() then print "runs="+runs+" i="+i+": need to GCCollect a little"
Next
If runs mod 100 = 0
Print GCMemAlloced()
EndIf
runs :+ 1
Until runs = 10000 (this never spits out that print-line - but commenting out the GCSetMode() line would result in the GCMemAlloced getting lower after some runs - because "auto gc" kicked in) |
Regarding GCCollectALittle ... blitz.mod/bdwgc/tests/gctest.c contains both calls - The code there is for example this: /* Garbage collect repeatedly so that all inaccessible objects */
/* can be finalized. */
while (GC_collect_a_little()) { }
for (i = 0; i < 16; i++) {
GC_gcollect();
# ifndef GC_NO_FINALIZATION
# ifdef FINALIZE_ON_DEMAND
late_finalize_count +=
# endif
GC_invoke_finalizers();
# endif So they mix it in this specific test - in other tests they simply call GC_gcollect() which means the users are ought to use GC_gcollect() in most situations - as we do. |
Just in case someone is tinkering with it ... you can receive some GC stats (pay attention that "print blabla" is allocating memory too... - so take care when printing out things during your loop iterations) local gcstats:SGCStats 'defined in brl.mod/blitz.mod/blitz.bmx
GCGetStats(gcstats)
print "GC Stats:"
print " heapsize: " + gcstats.heapsize 'Heap size in bytes (including the area unmapped to OS)
print " freeBytes: " + gcstats.freeBytes 'Total bytes contained in free and unmapped blocks.
print " unmappedByes: " + gcstats.unmappedBytes 'Amount of memory unmapped to OS.
print " bytesAllocedSinceGC: " + gcstats.bytesAllocedSinceGC 'Number of bytes allocated since the recent collection.
print " allocedBytesBeforeGC: " + gcstats.allocedBytesBeforeGC 'Number of bytes allocated before the recent garbage collection.
print " nonGCBytes: " + gcstats.nonGCBytes 'Number of bytes not considered candidates for garbage collection.
print " GCCycleNo: " + gcstats.GCCycleNo 'Garbage collection cycle number.
print " markersM1: " + gcstats.markersM1 'Number of marker threads (excluding the initiating one) (0 if single-threaded)
print " bytesReclaimedSinceGC: " + gcstats.bytesReclaimedSinceGC 'Approximate number of reclaimed bytes after recent GC.
print " reclaimedBytesBeforeGC: " + gcstats.reclaimedBytesBeforeGC 'Approximate number of bytes reclaimed before the recent garbage collection.
print " freedBytesSinceGC: " + gcstats.freedBytesSinceGC 'Number of bytes freed explicitly since the recent GC.
print " obtainedFromOSBytes: " + gcstats.obtainedFromOSBytes 'Total amount of memory obtained from OS, in bytes. I printed stats before running the "repeat" loop and another print afterwards:
seems Edit: that odd value is not an "wrong struct definition"-bug within NG - the GC itself spits it out too:
as the result should be of type "unsigned long" (on my linux box) according to this: #ifdef _WIN64
# if defined(__int64) && !defined(CPPCHECK)
typedef unsigned __int64 GC_word;
typedef __int64 GC_signed_word;
# else
typedef unsigned long long GC_word;
typedef long long GC_signed_word;
# endif
#else
typedef unsigned long GC_word;
typedef long GC_signed_word;
#endif |
Just to rule out an already fixed bug in the bdwgc lib itself I updated blitz.mod/bdwgc to the latest libatomic_ops (libatomic should be provided by the compiler now) and latest bdwgc from their git repo. Results stay the same - so either a config thing at our side or a still lurking bug in the bdwgc repo. Did someone of you already have a .c-file prepared to test it out more easily (config of the gc etc) ? |
Good day,
Seems there is an issue with bbMemAlloc & bbMemFree.
Works:
Leaks:
When using debug it works as expected.
Cheers.
The text was updated successfully, but these errors were encountered: