[Fixed]Bug #3993 - Memory leak in python3

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
sliptonic
Veteran
Posts: 3459
Joined: Tue Oct 25, 2011 10:46 pm
Location: Columbia, Missouri
Contact:

[Fixed]Bug #3993 - Memory leak in python3

Post by sliptonic »

I've noticed a memory leak in Path that caused my machine to go OOM overnight a couple times.
DeepSOIC showed that the leak shows up in Part-o-Magic as well if there's a lot of objects in the tree.

I started disabling parts of Path to track it down and finally got it to where I can reproduce the leak entirely outside Path with a macro.
To reproduce,
1) start FreeCAD clean
2) Execute the macro. This will create a 1000 cubes in the tree, create a command and workbench.
3) Watch memory usage for a minute or so and it should stabilize.
4) Switch to the new workbench and the memory will start climbing and not stabilize.

The bug seems to be related to the isActive() code. I can disable this and the leak doesn't happen. I think the leak is particularly noticable in Path because we use a use a lot of these isActive implementations.

The leak doesn't seem to happen in the Sketcher WB or any other workbench that I tested. Perhaps it's python related?

Code: Select all

import FreeCAD,FreeCADGui

class JunkWorkbench (Workbench):
    "Junk workbench"

    def __init__(self):
        self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/Path/Resources/icons/PathWorkbench.svg"
        self.__class__.MenuText = "Junk"
        self.__class__.ToolTip = "Junk workbench"

    def Initialize(self):
        self.appendToolbar("junk", ['MyCommand1'])

class MyTool:
    "My tool object"

    def Initialize(self):
        "This function is executed when FreeCAD starts"
        self.list = ["MyCommand1"] 
        self.appendToolbar("My Commands",self.list) 
        
    def GetResources(self):
        return {"MenuText": "My Command",
                "Accel": "Ctrl+M",
                "ToolTip": "My extraordinary command"}


    def IsActive(self):
        if FreeCAD.ActiveDocument is not None:
            for o in FreeCAD.ActiveDocument.Objects:
                if o.Name[:3] == "Job":
                        return True
        return False

    def Activated(self):
        pass
            # do something here...

# Add a bunch of objects to the tree
for i in range(1000):
  App.ActiveDocument.addObject('Part::Box')

# Create a command and a workbench and add the icon to a toolbar.
FreeCADGui.addCommand('MyCommand1',MyTool())
FreeCADGui.addWorkbench(JunkWorkbench())
Last edited by Kunda1 on Thu May 30, 2019 6:23 pm, edited 1 time in total.
wmayer
Founder
Posts: 20284
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Possible memory leak

Post by wmayer »

The leak doesn't seem to happen in the Sketcher WB or any other workbench that I tested. Perhaps it's python related?
I can confirm this behaviour with a Python3 build while with Python2 it doesn't happen.
wmayer
Founder
Posts: 20284
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Possible memory leak

Post by wmayer »

The relevant part of the leak is this part of the IsActive() function: if o.Name[:3] == "Job":
When I modify it to

Code: Select all

    def IsActive(self):
        if FreeCAD.ActiveDocument is not None:
            for o in FreeCAD.ActiveDocument.Objects:
                if False:
                    return True
        #        if o.Name[:3] == "Job":
        #                return True
        return False
then I don't see a leak.
wmayer
Founder
Posts: 20284
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Possible memory leak

Post by wmayer »

wmayer
Founder
Posts: 20284
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Possible memory leak

Post by wmayer »

Note to myself
Possible things to check:
  • Check Python API if behaviour of reference counting has changed
  • Check for possible problems in PyCXX
The tracking of attributes in PyObjectBase doesn't seem to cause it because when disabling it the leak still occurs.
wmayer
Founder
Posts: 20284
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Bug #3993 - Memory leak in python3

Post by wmayer »

Further testing revealed that apparently the class Py::String is the problem. When I modify the function DocumentObjectPy::staticCallback_getName to e.g. do return PyUnicode_FromString("Name"); then no leak can be observed.
wmayer
Founder
Posts: 20284
Joined: Thu Feb 19, 2009 10:32 am
Contact:

Re: Bug #3993 - Memory leak in python3

Post by wmayer »

Post Reply