-
Notifications
You must be signed in to change notification settings - Fork 235
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
Capture memory usage #2330
Comments
Not sure if you saw #1689, but I think this is a great feature of capture:
In other words, I think the first example you have is evidence that there's a leak, but in M2's interpreter. Also see #1728 (comment), where this was first noticed. |
Okay, after messing the code, it seems we are leaking |
Yes, dictionaries don't go away -- that's so the dictionary can be recovered from the frame, which contains an integer called the frame ID. An alternative (and perhaps better) way to do it would be for each frame to contain a pointer to its dictionary. |
Oh, I had assumed that when we call It would be great to also document how frames work along the way. |
The dictionary caching has nothing to do with being assigned to a symbol -- they are cached so the dictionary can be recovered from the frame id, and that could be done away with as I sketched above. (The dictionaries cached contain just symbols, not "symbol closures". It's the symbol closures that point to frames containing symbol values.) The number of dictionaries is limited -- once you have loaded all the code, no more dictionaries are made. Thus the non-collection of dictionaries is not a memory leak problem. |
Could you please explain or better yet the document this system somewhere on the wiki? Even starting with some common terminology would be good.
|
Incidentally |
Recall from LISP the notion of function closure, or simply closure. When one returns a function as a value, that function closure remembers the values of the variables at the time it was created. Here is an example in M2: i1 : f = x -> () -> x
o1 = f
o1 : FunctionClosure
i2 : g = f 33
o2 = g
o2 : FunctionClosure
i3 : g()
o3 = 33
i4 : h = f 44
o4 = h
o4 : FunctionClosure
i5 : h()
o5 = 44 The code Similarly, M2 has "symbol closures". Here is an example: i1 : f = x -> () -> symbol x
o1 = f
o1 : FunctionClosure
i2 : g = f 33
o2 = g
o2 : FunctionClosure
i3 : g()
o3 = x
o3 : Symbol
i4 : value oo
o4 = 33
i5 : h = f 44
o5 = h
o5 : FunctionClosure
i6 : h()
o6 = x
o6 : Symbol
i7 : value oo
o7 = 44 All the symbols appearing at top level are actually symbol closures in this sense. They contain a symbol and a pointer to the appropriate frame where the value is stored.
Ah, thanks for the reminder. So maybe it is time to implement the fix I proposed above. (On the other hand, dictionaries aren't very large, so it may not be urgent.) |
Not related to the testCode = ///
R = QQ[x,y,z];
x+1;
assert ( 1 == 1 )
///
scan(1000, i-> (capture(testCode,UserMode=>false);collectGarbage())); I can test it later but I'm fairly certain it's leaking the polynomial ring on every cycle, because if I replace the first line of the test code with nearly anything else, we don't leak anymore. I think this causes most tests to leak, since most tests create polynomial rings. |
Just to make sure, you're disabling Usermode, right? |
Yep, it's right there in the |
I think I figured this out. The problem is how |
Referencing a comment here:
Originally posted by @antonleykin in #2770 (comment) I wonder if after fixing the problem above, we could use capture to detect memory leaks from the frontend. |
capture
seems to have a slow memory leak. Running the following loop on my system increases M2's memory usage by ~0.5MB/s seemingly indefinitely. (I ran it till M2 was using 300MB).The following loop seems to leak much faster (1GB within 15min), but it's harder to figure out what's leaking:
In contrast the following loop does not cause an increase in memory usage:
Valgrind does not seem to detect a leak.
The text was updated successfully, but these errors were encountered: