[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.
User avatar
sliptonic
Posts: 1620
Joined: Tue Oct 25, 2011 10:46 pm

[Fixed]Bug #3993 - Memory leak in python3

Postby sliptonic » Wed May 29, 2019 6:25 pm

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
Site Admin
Posts: 15229
Joined: Thu Feb 19, 2009 10:32 am

Re: Possible memory leak

Postby wmayer » Thu May 30, 2019 3:49 pm

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
Site Admin
Posts: 15229
Joined: Thu Feb 19, 2009 10:32 am

Re: Possible memory leak

Postby wmayer » Thu May 30, 2019 4:06 pm

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
Site Admin
Posts: 15229
Joined: Thu Feb 19, 2009 10:32 am

Re: Possible memory leak

Postby wmayer » Thu May 30, 2019 4:24 pm

wmayer
Site Admin
Posts: 15229
Joined: Thu Feb 19, 2009 10:32 am

Re: Possible memory leak

Postby wmayer » Thu May 30, 2019 4:27 pm

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
Site Admin
Posts: 15229
Joined: Thu Feb 19, 2009 10:32 am

Re: Bug #3993 - Memory leak in python3

Postby wmayer » Mon Jun 24, 2019 9:36 am

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
Site Admin
Posts: 15229
Joined: Thu Feb 19, 2009 10:32 am

Re: Bug #3993 - Memory leak in python3

Postby wmayer » Mon Jun 24, 2019 12:31 pm