Re: Memory leak or flawed garbage collector
- To: mathgroup at smc.vnet.net
- Subject: [mg120678] Re: Memory leak or flawed garbage collector
- From: "Oleksandr Rasputinov" <oleksandr_rasputinov at hmamail.com>
- Date: Wed, 3 Aug 2011 07:07:58 -0400 (EDT)
- Delivered-to: l-mathgroup@mail-archive0.wolfram.com
- References: <j0u7mo$fc1$1@smc.vnet.net> <j10l01$os6$1@smc.vnet.net>
On Tue, 02 Aug 2011 12:12:37 +0100, Alexey Popkov <lehin.p at gmail.com> wrote: > "Oleksandr Rasputinov" <oleksandr_rasputinov at hmamail.com> wrote: > news:j15738$b4a$1 at smc.vnet.net... >> From this we may surmise that values are not being cleared for symbols >> appearing in a Module that have gone out of scope if the delayed flag is >> set and if they have also been conditionally evaluated. It appears that >> these values are what is preventing garbage collection; therefore I >> would >> consider this as a bug in Module (in that it does not recognise when >> values have gone out of scope in all cases) rather than in the garbage >> collector itself. > > Consider the following simple experiment without Module: > > In[1]:= $HistoryLength=0; > a[b_]:=(SetAttributes[d,Temporary];d:=9;d/;b===1); > > In[3]:= a[1] > Out[3]= 9 > > In[4]:= Definition[d] > Out[4]= Attributes[d]={Temporary} > > d:=9 > > As you see, the same bug appears without Module. So I think this is a > bug in the garbage collector itself. There is certainly some subtle behaviour going on here. The reason d is still around at the end of this is that it appears lexically in the input and is thus referred to by a. For example: In[1] := $HistoryLength = 0; x[y_] := ( (* to avoid referencing q explicitly *) SetAttributes[Evaluate@Symbol["q"], Temporary]; ); In[3]:= Names[$Context <> "*"] Out[3]= {"x", "y"} In[4] := x[1]; Names[$Context <> "*"] Out[5] = {"x", "y"} So as long as q isn't referred to directly, the garbage collector does its job and the symbol is removed immediately. (This is somewhat useless for practical purposes however as the symbol is created and destroyed so quickly that one cannot do anything with it.) On the other hand, in a new session: In[1] := $HistoryLength = 0; a[b_] := SetAttributes[d, Temporary]; In[3] := Names[$Context <> "*"] Out[3] = {"a", "b", "d"} (* even though we haven't done anything yet; reference count = 1 *) In[4] := a[1]; Names[$Context <> "*"] Out[4] = {"a", "b", "d"} (* no change; reference count still 1 *) In[5] := Clear[a]; Names[$Context <> "*"] Out[6] = {"a", "b"} (* reference count 0; it's gone *) So far all is as expected. But, in a new session: $HistoryLength = 0; a[b_] := ( SetAttributes[d, Temporary]; d := 9 (* we don't bother with the conditional evaluation *) ); In[3] := a[1]; Names[$Context <> "*"] Out[4] = {"a", "b", "d"} (* still as expected, per above *) In[5] := Clear[a]; Names[$Context <> "*"] Out[6] = {"a", "b", "d"} (* ??? *) In[7] := d = 9; (* delayed assignment changed to immediate *) Names[$Context <> "*"] Out[8] = {"a", "b"} (* gone *) So it seems that the conjectured "delayed flag" set by SetDelayed constitutes a reference to the symbol which prevents its being garbage-collected. Needless to say this is rather obscure from the user's point of view and could be considered a bug on that account, though there is presumably a justifiable reason for it. And, of course, you are correct that it is nothing to do with Module per se (which merely confuses the issue). > As for Module, I feel that this function is > essentially top-level, as opposed to Block. Probably it is possible to > write full analog of Module in top-level Mathematica code. Yes, I agree. >> Block >> also does not need to create and maintain temporary symbols, and >> therefore >> offers better performance than Module; it seems that this kind of >> lexical >> scoping is merely emulated in Mathematica, with dynamic scoping fitting >> more naturally with the language semantics. For these reasons, unless I >> explicitly require the temporary symbols, I generally prefer Block in >> most >> simple cases, or With where lexical scoping is called for. > > Interesting. I agree that Module looks a bit hacky from the point of > view of > the overall design of the system. As Richard Fateman wrote in his 1991 > year > paper "A review of Mathematica", Module was introduced in version 2 for > fixing inconsistent design of Block scoping and scoping in replacement > rules: defining > g[x_] := Block[{a}, a = 1 + x] > and then evaluating g[a] gives $RecursionLimit::"reclim" error instead of > 1+a. Module solves this problem. I'm not sure if I would call this "inconsistent". It is inconvenient, and perhaps unexpected to the uninitiated, but it seems to me essentially a result of mixing together constructs that imply lexical and dynamic scoping in a conflicting way. Module is, however, a good solution to the difficulties thus encountered.