ASE Home Page Products Download Purchase Support About ASE
ChartDirector Support
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  Segmentation fault with DrawArea under python - garbage collection?
Posted by Matt Hoskins on Dec-04-2014 17:32
Hi,

I use the python version of ChartDirector. The way my charting code is structured involves having some methods on my own classes which call DrawArea() to create draw areas which are drawn on and then used for e.g. LegendBox.addKey(). However those methods do not call makeChart for the chart - that's left up to a parent caller.

What I think is happening is that the ChartDirector dll is likely storing a reference to the DrawArea being passed in to e.g. LegendBox.addKey() but python is not aware of this. So when the method that calls DrawArea() exits python can garbage collect the DrawArea object not realising that the ChartDirector dll has a reference to it. When e.g. makeChart is later called the segmentation fault occurs when the ChartDirector dll tries to make use of the reference to the now garbage collected DrawArea.

I've been able to work around it by just adding a list object to the python XYChart object and appending any DrawAreas I allocate to that to ensure they're not garbage collected before the XYChart object. So e.g. this contrived example will segmentation fault for me:


from pychartdir import *
def testEntry(c):
        lb = c.addLegend(0,0)
        da = DrawArea()
        da.setSize(12,12,0x0)
        lb.addKey('Test',0x0,0,da)
c=XYChart(100,100)
testEntry(c)
c.makeChart('test.png')

This tweaked version of the contrived example will work:

from pychartdir import *
def testEntry(c):
        lb = c.addLegend(0,0)
        da = DrawArea()
        c.track_da.append(da)
        da.setSize(12,12,0x0)
        lb.addKey('Test',0x0,0,da)
c=XYChart(100,100)
c.track_da = []
testEntry(c)
c.makeChart('test.png')


It may well be an issue you're aware of already, and I can work around it using techniques like the one above to prevent the DrawAreas being swept up too early, but as I couldn't see it mentioned in the docs and a quick search of the support forum didn't show anything up I thought I'd report it!

Regards,
Matt

  Re: Segmentation fault with DrawArea under python - garbage collection?
Posted by Peter Kwan on Dec-04-2014 23:57
Hi Matt,

You are absolutely correct. If multiple objects are created in Python directly (by calling
constructors such as  DrawArea() or XYChart()), and they somehow become dependent,
all of them should remain in Python scope when the chart is rendered (calling makeChart).
Otherwise, Python may garbage collect or free some of them, breaking the other objects
dependent on them.

We have built-in fix for the common case of including multiple charts in a MultiChart
object,  using essentially the same approach as in your code (by using an array to hold
the reference).

We have not yet fixed the less common cases because of the difficulties in keep tracking
how an object originates. In your current case, the issue can be solved by keeping a
reference to DrawArea, as the DrawArea is created directly in Python code.  However,
the DrawArea can also be obtained in other ways, such as from a BaseChart object by
calling BaseChart.makeChart3. In this case, keeping the reference to the DrawArea is not
useful. We need to keep the reference to the underlying BaseChart object, as the
DrawArea object will be destroyed when the underlying BaseChart is garbage collected.

A further complication is that some versions of Python can use "reference counting"
instead of garbage collection. In complicated cases, keeping references can result in
circular references, leading to memory leaks.

We are investigating how to best solve the problem in general. In the mean time, to work
around, the charting code would need to ensure all dependent objects exist when the
chart is rendered.

Regards
Peter Kwan