[Nauty] Memory leaks
Brendan McKay
brendan.mckay at anu.edu.au
Mon Aug 13 17:38:12 AEST 2018
Yes, it would be feasible to use a system of free lists instead of the
present system.
I should have mentioned that despite improvements in memory allocation
code since the Good Old Days, there has also been a loss due to the need
for malloc/free to be thread-safe.
I'm hoping that my new design the stack for small arrays will mostly
avoid that and also give some caching improvement from address
proximity. It will also give re-entrance without thread-local
variables. I plan to start testing it fairly soon.
Brendan.
On 13/08/18 16:43, Matthias Walter wrote:
> Hi Brendan,
>
> thank you for the (quick!) clarification. Good to hear that there is
> no real leak. Your explanation sounds like one could in principle add
> a method to clean-up all these helper structures such as free lists,
> etc., right?
>
> Best,
> Matthias
>
> On 12.08.2018 14:38, Brendan McKay wrote:
>>
>> Hi Matthias,
>>
>> What you see is not a memory leak even though valgrind is suspicious
>> of it.
>>
>> I'm appending mail I sent to Marco a short time ago which explains it.
>>
>> To check there is really no leak, I compiled nautyex3.c exactly as
>> distributed except for disabling the output to stdout, (i.e. without
>> the DYNFREE insertions that you made), and I ran it like this:
>>
>> %%% (for n in `seq 1 1000000` ; do echo 1000 ; done) | nautyex3
>>
>> After about 15 minutes the memory usage is still exactly the same as
>> it was after the first few seconds, according to both 'top' and
>> /proc/PID/statm . So the program is reusing the allocated memory as
>> intended, and never losing any of it.
>>
>> Hope that helps.
>> Brendan.
>>
>> --------------------------------------------------
>>
>> The thing about those allocations is that if you call the same
>> functions again, the same memory will be reused. So they aren't
>> strictly leaks, though they are problematic.
>>
>> The problem being addressed is that for very simple functions with
>> dynamic allocation, the time will be dominated by the cost of
>> allocation and freeing. Also, in practice the same functions tend to
>> be called multiple times with the same graph size. So a long time
>> (decades) ago I got the idea of doing the allocation once and keeping
>> the memory for future calls. When I first implemented this, some
>> things got much faster.
>>
>> Today with multi-thread programming being normal, this method is not
>> so great. I have detailed plans for a new scheme which uses the
>> stack for small arrays and malloc/free for large arrays, but I didn't
>> have time to implement it yet.
>>
>> Of course, if you find a case where the memory in use keeps growing
>> without limit, that's an error and I'd appreciate knowing about it.
>>
>>
>> On 12/8/18 9:43 pm, Matthias Walter wrote:
>>> Dear developers,
>>>
>>> we are using nauty (27b11) for a project and observed several memory
>>> leaks occuring in the densenauty() call. Is there a way to free this
>>> memory? To reproduce this bug we considered the nautyex3.c example
>>> and added
>>>
>>> DYNFREE(g,g_sz);
>>> DYNFREE(lab,lab_sz);
>>> DYNFREE(ptn,ptn_sz);
>>> DYNFREE(orbits,orbits_sz);
>>>
>>> after the allgroup() call to free the memory that we allocated
>>> explicitly. Using valgrind, we observe the following leaks after
>>> running it with n=1 and aborting with n=-1 afterwards.
>>>
>>> Best,
>>> Matthias
>>>
>>> ==26840==
>>> ==26840== HEAP SUMMARY:
>>> ==26840== in use at exit: 1,124 bytes in 19 blocks
>>> ==26840== total heap usage: 25 allocs, 6 frees, 3,192 bytes allocated
>>> ==26840==
>>> ==26840== 4 bytes in 1 blocks are still reachable in loss record 1
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x402B17: nauty (nauty.c:358)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 4 bytes in 1 blocks are still reachable in loss record 2
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x402B65: nauty (nauty.c:359)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 4 bytes in 1 blocks are still reachable in loss record 3
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x402BB3: nauty (nauty.c:360)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 4 bytes in 1 blocks are still reachable in loss record 4
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x404216: doref (nautil.c:492)
>>> ==26840== by 0x401C74: firstpathnode0 (nauty.c:591)
>>> ==26840== by 0x4031D5: nauty (nauty.c:498)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 4 bytes in 1 blocks are still reachable in loss record 5
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x4055A2: refine1 (naugraph.c:352)
>>> ==26840== by 0x40428C: doref (nautil.c:497)
>>> ==26840== by 0x401C74: firstpathnode0 (nauty.c:591)
>>> ==26840== by 0x4031D5: nauty (nauty.c:498)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 4 bytes in 1 blocks are still reachable in loss record 6
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x408773: makecosetreps (naugroup.c:222)
>>> ==26840== by 0x400C98: main (nautyex3.c:71)
>>> ==26840==
>>> ==26840== 4 bytes in 1 blocks are still reachable in loss record 7
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x4087BA: makecosetreps (naugroup.c:223)
>>> ==26840== by 0x400C98: main (nautyex3.c:71)
>>> ==26840==
>>> ==26840== 4 bytes in 1 blocks are still reachable in loss record 8
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x408C69: allgroup (naugroup.c:376)
>>> ==26840== by 0x400CA5: main (nautyex3.c:76)
>>> ==26840==
>>> ==26840== 6 bytes in 1 blocks are still reachable in loss record 9
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x402C03: nauty (nauty.c:361)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 6 bytes in 1 blocks are still reachable in loss record 10
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x402C53: nauty (nauty.c:362)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 8 bytes in 1 blocks are still reachable in loss record 11
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x402A7B: nauty (nauty.c:356)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 8 bytes in 1 blocks are still reachable in loss record 12
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x402AC9: nauty (nauty.c:357)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 8 bytes in 1 blocks are still reachable in loss record 13
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x401BC2: firstpathnode0 (nauty.c:578)
>>> ==26840== by 0x4031D5: nauty (nauty.c:498)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 12 bytes in 1 blocks are still reachable in loss record 14
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x402CA7: nauty (nauty.c:363)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 12 bytes in 1 blocks are still reachable in loss record 15
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x4055F6: refine1 (naugraph.c:353)
>>> ==26840== by 0x40428C: doref (nautil.c:497)
>>> ==26840== by 0x401C74: firstpathnode0 (nauty.c:591)
>>> ==26840== by 0x4031D5: nauty (nauty.c:498)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 16 bytes in 1 blocks are still reachable in loss record 16
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x402A2D: nauty (nauty.c:355)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 16 bytes in 1 blocks are still reachable in loss record 17
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x401BA5: firstpathnode0 (nauty.c:576)
>>> ==26840== by 0x4031D5: nauty (nauty.c:498)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 40 bytes in 1 blocks are still reachable in loss record 18
>>> of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x408667: grouplevelproc (naugroup.c:181)
>>> ==26840== by 0x401EC2: firstpathnode0 (nauty.c:625)
>>> ==26840== by 0x4031D5: nauty (nauty.c:498)
>>> ==26840== by 0x405CD2: densenauty (naugraph.c:657)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== 960 bytes in 1 blocks are still reachable in loss record
>>> 19 of 19
>>> ==26840== at 0x4C2DB8F: malloc (in
>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>> ==26840== by 0x405C89: densenauty (naugraph.c:654)
>>> ==26840== by 0x400C7F: main (nautyex3.c:57)
>>> ==26840==
>>> ==26840== LEAK SUMMARY:
>>> ==26840== definitely lost: 0 bytes in 0 blocks
>>> ==26840== indirectly lost: 0 bytes in 0 blocks
>>> ==26840== possibly lost: 0 bytes in 0 blocks
>>> ==26840== still reachable: 1,124 bytes in 19 blocks
>>> ==26840== suppressed: 0 bytes in 0 blocks
>>> ==26840==
>>> ==26840== For counts of detected and suppressed errors, rerun with: -v
>>> ==26840== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0
>>> from 0)
>>>
>>> _______________________________________________
>>> Nauty mailing list
>>> Nauty at anu.edu.au
>>> http://mailman.anu.edu.au/mailman/listinfo/nauty
>
> _______________________________________________
> Nauty mailing list
> Nauty at anu.edu.au
> http://mailman.anu.edu.au/mailman/listinfo/nauty
More information about the Nauty
mailing list