Re: Out of memory using chart::clicker
by Laurent_R (Canon) on Feb 20, 2014 at 22:30 UTC
|
Hmm, I don't know anything about for Chart::Clicker, but it seems that you have a memory leak. When you do this:
for (my $x=0;$x<10000;$x++) {
&mysub(\@x_axis, \@{$a_hash{abc}});
print ".";
}
mysub will create 10000 objects, which should not be a problem so long as the objects have only a few hundreds of numerical data. But if your module stores also the generated graph, then you might be creating objects that are 100 kB large (or more). And then, you might run into a problem if the created objects are persistent and not released between two calls. I would suggest that you try to let each dataset fall out of scope between two calls. This way, presumably, Perl will release the memory each time and you should not have any trouble.
Passing lexical copies of the arrays, rather than the references, might be the way to go.
| [reply] [d/l] |
|
|
Thanks, I think you hit the nub of my confusion here. Since mysub is a sub and I am calling it, when it returns I thought everything it created itself (like I assume a large bitmap of the graph in an array for instance) got released? I guess thats dependent on everything inside that sub being lexical. But if chart::clicker complies with use strict, surely it would not compile if it contained non lexical variables (unless there is a no strict in chart clicker somewhere but I can't find it if there is).
So I added use strict to the test script and realised I didn't define $x and $y inside the sub as lexical, fixed that and rerun the test and got the same result (out of mem).
I don't want to copy each array if possible as theres a lot of data to be copied (actually now I realise copying won't really help). I can see that there is a different way to code this by not originally using a large multidimensional hash to sort my data in the first place, but using hashes makes the coding much easier (at least with my present mindset - maybe if I had originally thought of the problem differently it would be fine) - but, surely it should be possible to use hashes in this way?
Re letting the dataset fall out of scope, is there a way of doing this without copying the array each iteration? I don't need the array once the sub has finished with it. I tried undefing after the call to mysub (in the original code each array ref passed into mysub was a different array hash element IE @{$hash{x}{y{z}}) so I used
$mysub(\@{$hash{x}{y{z}});
undef @{$hash{x}{y{z}};
but that didn't seem to work but maybe my method was incorrect.
I guess memory leak questions are common but are there any obvious things I am doing wrong here? Is this a leak in the chart module resulting in simply not being able to use it so many times in the same execution? | [reply] [d/l] |
|
|
Yes, you are most probably right, since you are calling Chart::Clicker in a sub, what you do there should have lexical scope and allocated memory should be redeemed when you exit the sub as the references to objects fall out of scope. So, I somewhat overlooked part of what you are doing in your program and,as far as I can say, you do not seem to be doing anything wrong. It would appear, then, that the memory leak (if any, but it definitely looks so) probably occurs in the module you are calling or possibly in another module called by it.
The solution (or rather workaround), that I used a couple of times in the past in vaguely similar situations, might be to have your Perl program process, say, a couple of hundred of datasets and then die (using the exec function or maybe forking before dieing or possibly doing it in a shell loop or some other similar means, I just remember I tried various possibilities and I don't remember exactly which one worked, and I can't check the final program before returning to work on Monday) after having called itself with parameters for the next group of datasets, and so on until your are done. This approach is far from being pretty, but, it seems to work.
Update : Actually, I had not yet seen it when I just wrote the above, but davido said it before me and I can only agree with him: yes, forking and suiciding immediately after seems to be a good solution temporary fix.
| [reply] [d/l] |
|
|
|
|
Re: Out of memory using chart::clicker
by davido (Cardinal) on Feb 21, 2014 at 18:01 UTC
|
I think that the long answer and the short answer are both that Chart::Clicker is leaking memory. Maybe not leaking in its own code, but somewhere between the primary module and its dependencies, there's a leak. I don't see in your code anything that you are doing seriously wrong. When you pass to an object's constructor a reference to an array, and later let that object fall out of scope, whether or not the array is still in scope should never affect the object's ability to be destroyed, freeing up its memory. My first suspicion was that the ref to the array was somehow being tied inside the object to a class that created a circular reference. But I don't see any use of tie; just a lot of Moose. However, the dependency chain is fairly heavy, and I didn't work my way up the chain in every direction in my effort to track down the culprit.
If it were me, I would try to boil it down to an even smaller test case that demonstrates the leak, and submit it as a bug report via Chart::Clicker's RT. The author knows his code base and dependencies better than you. Certainly authors appreciate actionable reports -- ones where you've done the research and created a patch for them. And if you have the ambition to do that, I'm sure it would be welcomed. But at minimum, at least submit a report demonstrating the bad behavior.
As for a temporary fix: The time honored solution is to fork children, work work work, then let them report back, and ultimately each one exits. By instantiating your Chart::Clicker objects inside of short-lived child processes, you never get into a situation where a memory leak in Chart::Clicker has a long enough life to become a problem. It's an ugly truth, but it works.
| [reply] |
|
|
I have previously run into the same memory leak issue issue with Chart::Clicker. As you noted, it has a fairly heavy dependency chain. I didn't get very far trying to follow it. This was for a project at $WORK and I need to get things done.
My work around was exactly as you said: fork off children to do the work. This was just a one off for exploration, so I didn't spend much time trying to optimize it. I forked a child for each chart, and kept the total child count under $n for some appropriate value of $n.
| [reply] |
|
|
Just a small example of memory leak
#!/usr/bin/perl
use strict;
use Chart::Clicker;
use Chart::Clicker::Context;
use Chart::Clicker::Data::Range;
use Chart::Clicker::Renderer::Bubble;
use Chart::Clicker::Data::DataSet;
use Chart::Clicker::Data::Series::Size;
print "run 'top' in linux and look in perl process!\n";
my $j = 100000000;
for (my $i =1;$i < $j;$i+=1){
print "$i iteration\n";
mysub($i);
}
sub mysub{
my ($var_i) = @_;
my @k = (1,2,3);
my $cc = Chart::Clicker->new(width => 800, height => 400 , format
+=> 'png', padding => 10);
my $series = Chart::Clicker::Data::Series::Size->new(
keys => \@k,
values => \@k,
sizes => \@k,
name => "$var_i",
);
my $ds = Chart::Clicker::Data::DataSet->new(
series => [ $series ]
);
$cc->add_to_datasets($ds);
my $defctx = $cc->get_context('default');
$defctx->renderer(Chart::Clicker::Renderer::Bubble->new);
$cc->write_output($var_i);
#undef $cc;
print "\tmemory leak after 'cc->write_output'\n";
}
I can't find any solution and need quick help. I don't want to use any other perl chart lib. But I think I have no choice. :(
With pleasure
BorisPlus | [reply] [d/l] |
|
|
|
|
|
|
Re: Out of memory using chart::clicker
by zentara (Cardinal) on Feb 21, 2014 at 17:46 UTC
|
Just from glancing at your code, and knowing what memory gluttens packages are, I can see one giant problem. You have a loop which makes 10000 iterations, and in each cycle, you create a new $chart object and it's associated helper objects.
For some reason, I believe your sub mysub{} closure isn't cleaning up all those objects, as you would expect. In my experience with other graphic modules, this can be avoided by creating only 1 set of global objects, and as you go thru your loops, you clean out and reuse the global object. This prevents the memory problem ... reuse your objects. See perldoc -q clear for how to clear a package. MJD's example code cleans out a package for reuse.
| [reply] |
|
|
I've got to say, that sounds like a really good thing to try which I never thought of myself. If I am writing something heavy from scratch myself I would use this kind of technique (I always try to think of reducing allocation overhead etc even though I don't know if it really helps in perl but I always have c in the back of my mind) but it just didn't occur to try it this time as I was thinking along the lines of 'must start with new object each time to make sure its nice and clean'. I guess its dependent on the module code working properly though otherwise things like reused arrays of a smaller size second time round might still contain some old data? Regardless it will be an interesting test to run. Thanks
| [reply] |
Re: Out of memory using chart::clicker
by djzort (Sexton) on Mar 20, 2014 at 04:05 UTC
|
It seems that Chart::Clicker is creating circular references which perl can't unpick.
Using Chart::Clicker via Catalyst, and +CatalystX::LeakChecker
[debug] Circular reference detected:
.---------------------------------------------------------------------
+---.
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[0]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[0]->{component_list}->{compone
+n- |
| ts}->[0]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[0]->{component_list}->{compone
+n- |
| ts}->[1]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[0]->{component_list}->{compone
+n- |
| ts}->[2]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[0]->{component_list}->{compone
+n- |
| ts}->[3]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[0]->{component_list}->{compone
+n- |
| ts}->[4]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[0]->{component_list}->{compone
+n- |
| ts}->[5]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[0]->{component_list}->{compone
+n- |
| ts}->[6]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[0]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[1]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[2]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[3]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[4]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[5]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[6]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[7]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[8]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[9]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[1]->{component_list}->{compone
+n- |
| ts}->[10]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[2]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[2]->{component_list}->{compone
+n- |
| ts}->[0]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[2]->{component_list}->{compone
+n- |
| ts}->[1]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{component_list}->{components}->[2]->{component_list}->{compone
+n- |
| ts}->[2]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{grid}->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{render_area}->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{render_area}->{component_list}->{components}->[0]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{render_area}->{component_list}->{components}->[1]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [0]->{render_area}->{component_list}->{components}->[2]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [1]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [1]->{component_list}->{components}->[0]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [1]->{component_list}->{components}->[1]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [1]->{component_list}->{components}->[2]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [1]->{component_list}->{components}->[3]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{component_list}->{components}-
+>- |
| [2]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{domain_
+a- |
| xis}->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{domain_
+a- |
| xis}->{component_list}->{components}->[0]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{domain_
+a- |
| xis}->{component_list}->{components}->[1]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{domain_
+a- |
| xis}->{component_list}->{components}->[2]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{domain_
+a- |
| xis}->{component_list}->{components}->[3]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{domain_
+a- |
| xis}->{component_list}->{components}->[4]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{domain_
+a- |
| xis}->{component_list}->{components}->[5]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{domain_
+a- |
| xis}->{component_list}->{components}->[6]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[0]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[1]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[2]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[3]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[4]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[5]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[6]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[7]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[8]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[9]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{range_a
+x- |
| is}->{component_list}->{components}->[10]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{contexts}->{default}->{rendere
+r- |
| }->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{legend}->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{legend}->{component_list}->{co
+m- |
| ponents}->[0]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{legend}->{component_list}->{co
+m- |
| ponents}->[1]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{legend}->{component_list}->{co
+m- |
| ponents}->[2]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{legend}->{component_list}->{co
+m- |
| ponents}->[3]->{layout}->{component}
+ |
| $ctx->{stash}->{graphics_primitive}->{marker_overlay}->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[0]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[0]->{component_list}->{components}->[0]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[0]->{component_list}->{components}->[1]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[0]->{component_list}->{components}->[2]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[0]->{component_list}->{components}->[3]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[0]->{component_list}->{components}->[4]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[0]->{component_list}->{components}->[5]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[0]->{component_list}->{components}->[6]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[0]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[1]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[2]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[3]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[4]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[5]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[6]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[7]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[8]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[9]->{layout}->{compone
+n- |
| t}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[1]->{component_list}->{components}->[10]->{layout}->{compon
+e- |
| nt}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[2]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[2]->{component_list}->{components}->[0]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[2]->{component_list}->{components}->[1]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{component_list}->{comp
+o- |
| nents}->[2]->{component_list}->{components}->[2]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{grid}->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{render_area}->{clicker
+} |
| $ctx->{stash}->{graphics_primitive}->{plot}->{render_area}->{compone
+n- |
| t_list}->{components}->[0]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{render_area}->{compone
+n- |
| t_list}->{components}->[1]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{plot}->{render_area}->{compone
+n- |
| t_list}->{components}->[2]->{clicker}
+ |
| $ctx->{stash}->{graphics_primitive}->{title}->{layout}->{component}
+ |
'---------------------------------------------------------------------
+---'
| [reply] [d/l] |
|
|
# hack away at circular references!
$chart->{component_list}->{components} = undef;
$chart->{'contexts'}{'default'}{'range_axis'}{'parent'}{'component
+_list'}{'components'} = undef;
$chart->{legend}->{component_list}->{components} = undef;
$chart->{plot} = undef;
$chart->{contexts}->{default} = undef;
$chart->{legend}->{clicker} = undef;
$chart->{marker_overlay}->{clicker} = undef;
$chart->{title}->{layout}->{component} = undef;
| [reply] [d/l] |
|
|
I've released new versions of Graphics::Primitive (0.65) and Chart::Clicker (2.88) that seek to address this issue. If you still see leaks I'd appreciate another dump form the leakchecker. That was quite helpful.
| [reply] |