"Konovalov, Vadim" <[EMAIL PROTECTED]> writes: > > Commenting out the print removes the reference to %wids which makes > > "sub {...}" just return a constant that lives in perl's OP-tree. It > > is only when there are references to outer lexicals that "sub {...}" > > returns a fresh CV each time it executes. > > good catch; now I no more thinking of this as of a mysterious case...
Good. > > Compare the output of these: > > > > perl -le 'my $a = 1; print map sub { $a }, 1..3' > > perl -le ' $a = 1; print map sub { $a }, 1..3' > > > > So without the reference to %wids the CV is kept alive because it > > lives in perl's OP-tree and everything is fine. With the %wids > > reference the sub only lives as long as the Tcl "perlsub" object keeps > > it alive. > > > > I added some prints to the "perlsub" destructor (FreePerlSub in > > Tcl.xs) and noticed that the sub is freed the first time the callback > > command executes. > > > > So what happens is that the button store the "perlsub" object just > > fine, but when the object is passed to Tcl_EvalObjEx() in > > TkInvokeButton() the first time then the object is mutated into a > > ByteCodeObj and at this point the CV reference is dropped. Too bad. > > I beleive there could be some sort of optimization when some things are done > at first invoke, and never done if subroutine never called... > But this is irrelevant in our case, I beleive. I don't find it irrelevant since it's this that makes Tcl drop ownership of the perl CV. > > Perhaps there is no hope for getting rid of %anon_refs and the current > > CV leakage. > > I think current situation with CVs destroying too early isn't wrong: > you didn't marked CV as used by Tcl interpreter, so Perl frees it as > CV goes out of scope. Not true, the CV is marked as used by Tcl: The NewPerlSubObj() function in my version of Tcl.xs will SvREFCNT_inc the CV so it stays alive as long as Tcl holds on to the "perlsub" object. The problem is that Tcl destorys the "perlsub" object when it is mutated into a "bytecode" object. > But, as long as sub *is* needed in Tcl, it should be referenced somehow. That is certainly the goal. > I see two ways of doing things: > - use "trace add command /name/ delete ..." as a proper place to decrement > refcount; (or delete from %anon_refs); Potentially, but you still have the problem of making Tcl actually delete the command when no more callback refrence it. > - keep Tcl-interpreter-wise %anon_refs, and delete all references from it > when interpreter is destroyed. I don't see much point in this as the Tcl interpreter will usually live as long as the app lives. At the point when the application exists it is no point in cleaning up "leaks". > It is makes sence to understand (by code exmaples) why we really need > "precise" refcounting; do you have trouble with leakage in some > applications? Consider this program destilled from the code that updates the status bar in our applications: ----------------------------------------------------------------->%------- #!/usr/bin/perl -w use Tkx; my $mw = Tkx::widget->new("."); my $count; my $after_handle; my $lab = $mw->new_label(); my $but = $mw->new_button( -text => "Hit me", -command => sub { $count++; message("Hit $count"); }, ); Tkx::pack($lab, $but); Tkx::MainLoop(); print Tkx::info_commands("::perl::*"), "\n"; sub message { my $msg = shift; $lab->configure(-text => $msg); if ($after_handle) { Tkx::after_cancel($after_handle); $after_handle = undef; } if ($msg ne "") { $after_handle = Tkx::after(1000, [\&message, ""]); } } ----------------------------------------------------------------->%------- This will show a message for 1 second and then clear it. The problem here is that each time you hit the button the Tcl layer produce a new CV for the after callback which is then leaked after the callback is called and forgot by Tcl. The final print is there to show how many ::perl::CODE... commands have been created. Hit the button many times and you get plenty. Since this kind of leak only happens with the speed of a human user it is not likely to make the app slow or run out of memory, but this can certainly happen if you use after callbacks for driving an animation for instance. In the example above the leak can be avoided by rewriting the statement as: if ($msg ne "") { $after_handle = Tkx::after(1000, sub { message("") }); } But in the our application we needed the first array form (or a real closure) becase the call also referenced some object so I do think this is a real problem. --Gisle