M2
M2 copied to clipboard
Memory leak in creating a sequence
I believe the following line has a memory leak:
f = () -> (scan(0..10^7, i -> ());)
At least it seems like after several times running f(), M2 grinds to a halt.
I should say, even running:
a = (1..10^7);
clearAll()
collectGarbage()
several times seems to do the same, so maybe this is something else? (I'm assuming clearAll and collectGarbage do something, right?)
cc: @jkyang92
The problem is that even in a line with a semicolon at the end, the value of the expression is saved. Compare:
i13 : 4;
i14 : o13
o14 = 4
i15 : (4;)
i16 : o15
o16 = o15
o16 : Symbol
The value of the output is one object. How can it possibly require gigabytes of memory? That doesn't explain the scan example either, where the value that goes in the first parameter of scan isn't saved in any accessible dictionaries.
Yes, but you said you ran it several times. And every top level expression has an integer stored with it, to indicate what sort of thing it actually is. And an element of ZZ is represented by a pointer to an object returned by mpir or gmp, which contains a length field, too. And there is overhead in libgc -- it has to keep track of the locations and lengths of all allocated objects, for later freeing. Suppose that adds up to 100 bytes -- then 10^7 of those is a gigabyte.
@mahrud Is this kind of what you did?
i1 : f = () -> scan(0..10^7, i -> ())
o1 = f
o1 : FunctionClosure
i2 : elapsedTime f()
-- 1.12672 seconds elapsed
i3 : for i from 1 to 100 do f()
This doesn't seem to leak to me (uses consistently 1.37 GB). That said, maybe it would be nice if 1..10^7 would not expand before the loop?
By several times I meant like 3 times!
i1 : run "free -h"
total used free shared buff/cache available
Mem: 15Gi 6.4Gi 1.4Gi 1.4Gi 7.7Gi 7.3Gi
Swap: 23Gi 1.6Gi 22Gi
o1 = 0
i2 : f = () -> (scan(0..10^7, i -> ()););
i3 : f();
i4 : f();
i5 : f();
i6 : run "free -h"
total used free shared buff/cache available
Mem: 15Gi 8.5Gi 224Mi 1.4Gi 6.8Gi 5.2Gi
Swap: 23Gi 1.6Gi 22Gi
o6 = 0