Running the loop
while 1 {
interp create i
interp delete i
}
results in process memory growing endlessly.
Miguel Sofer and I have been discussing the bug
at length in email and the Tcl'ers Chat and have
reached the conclusion that the problem arises when
a proc's bytecode representation lives until the interp
is deleted (generally, because some shared literal
has an internal representation of tclLocalVarType
that designates a variable in the proc).
I now suspect that the problem is ameliorated if
internal representations of global literals are destroyed
earlier in the process of taking down an interp.
I'm developing a patch to test this hypothesis.
Logged In: YES
user_id=99768
The attached patch appears to correct the problem
as described.
Patch to free literal internal reps early.
Logged In: YES
user_id=148712
The patch has been committed, ticket still open until I
reach a full understanding of the issue and am satisfied of
its correction and completeness. Issues:
(0) I still do not see why the leak was only observable in
windows.
(1) it frees the internal rep of every shared literal, but
unshared literals are not covered. This will break any
reference loop where a shared literal intervenes, but leaves
the issue untouched for loops of unshared lits
(2) it panics on a literal with no string rep; this can only
occur with unshared literals created via TclAddLiteralObj(),
so it is not really an issue while issue (1) remains untouched
Logged In: YES
user_id=148712
Committed a change in tclLocalVarnameType that removes the
reference to the proc, and hence renders these circular
references impossible.
Closing the ticket, the bug is now fixed twice over ;)
Miguel, can you comment on what importance
the call to TclCleanupLiteralTable() still has?
Chatlogs:
dgp For when I get back, I'm curious about the purpose of TclCleanupLiteralTable().
kbk dgp - ISTR that the literal table is one case where it's possible that Tcl_Obj's' int-reps can hold references to each other, and that a bespoke cleanup was needed to break cycles and actually kill them, but I may
dgp here's my observations
dgp TCLT() is called in only one place, DeleteInterpProc(.) in tclBasic.c
dgp About 100 lines later in the same DIP(.) routine, TclDeleteLiteralTable() is called.
dgp TCLT only removes intreps of literal values.
dgp TDLT actually frees them, which would destroy intreps if any were still around.
dgp The value of the TCLT pass is not clear to me.
dgp Commenting it out has no effect on the success of the test suite.
dgp hmmm, TCLT is not in Tcl 8.4, so the history of its origin ought to be findable....
kbk's fix for [Bug 994838]. See http://core.tcl.tk/tcl/info/460aa80311bfa1259a4562d35e5a40558e9a019d
Yes, kbk did that to fix (work around?) a leak tearing down interps.
Then you fixed the underlying cause shortly afterward.
http://core.tcl.tk/tcl/info/63de804c96
After that, TclCleanupLiteralTable() can be
removed. I'd like to do so. Why have code
you don't need? But I want to know what others
think. Are we keeping it around just as another
layer of protection in case another similar bug
pops up?
Agreed: remove
Agreed. It was a hack to deal with circular Tcl_Obj references. Miguel fixed the circular references. It can go.