Leaked elements detected - possibly solved

Discussion about using Python with libRocket.

Leaked elements detected - possibly solved

Postby feltech on Fri Apr 24, 2015 7:45 pm

Hey all. I'm a newcomer to libRocket but love it so far. I have (or rather, had) an annoying problem using the python bindings though.

In brief, I used Cython to create a Python binding to a stripped down version of the C++ SFML2 libRocket sample project. I then use this to tie together the libRocket Python bindings and pySFML.

I have things set up so I can either run Python embedded in my C++ app (my intended main usage, and very handy for dual Python/C++ debugging), or run my Python scripts via the system interpreter (very handy for one-off test cases).

May be worth noting that I am using the latest master from git and doing my development and debugging in eclipse on Ubuntu.

My little "hello world" test case looks like the following:
Code: Select all
from felt.lib.rocket import rocket
from felt.lib.sfml import sf
from felt.lib.PyRktSFMLInterface import PyRktSFMLInterface as RktSFML


def runWindow():
   window = sf.RenderWindow(sf.VideoMode(640, 480), "pySFML Window")
   rktSFML = RktSFML(window)
   
   # Necessary to ensure context is unloaded before rocket-SFML interface.
   def doWindow():
      context = rocket.CreateContext("default", rocket.Vector2i(640, 480))
      rktSFML.rktInit(context)
      rktSFML.rktInitDebugger()   
      document = context.LoadDocument('assets/demo.rml')         
      document.Show()

      while window.is_open:      
         for event in window.events:
            rktSFML.rktEvent(event)
            if type(event) is sf.CloseEvent:
               window.close()
         context.Update()
         window.clear()
         context.Render()
         window.display()            
               
   doWindow()   


if __name__ == "__main__":
   runWindow()


To get this running well, I have had to fix two things:
  • As you may see from the code above, there is a "double wrapping" of the context creation and event loop (the `doWindow` function). This is required to ensure the `context` is released before the `rktSFML` object. If I remove the `doWindow` wrapper, then I get an error "Context 'default' still active on shutdown" and "10 leaked elements detected." (followed by a list of all elements in the document).
  • With the fix above, I can remove the "Context 'default' still active on shutdown" error, but I still get the "leaked elements detected" error. Now, I spent many many days tracking this leak (using aforementioned embedded Python so I could debug through the C++ code). It turned out that the Python reference count is never decremented to zero, even though the C++ reference count is.
The best candidate I found for where a leak may be originating from is `ElementDocumentWrapper`'s constructor, the line `PyDict_SetItemString(module_namespace, "document", self)`. This increments the Python reference count, and when I add a `Py_DECREF(self)` after it, suddenly the leak disappears!

Of course, like I say I'm new to libRocket, so I'm not sure if what I've done will break things as I start to use libRocket more. One theory I have is that the `ElementDocumentWrapper` constructor is deliberately adding the document to a global module namespace (or something) so perhaps it's not supposed to be destroyed until the whole module is destroyed, and the debugger is just being premature in reporting a leak?

Any hints on how to better solve the above problems (or confirmation that my fixes are correct) would be much appreciated!

Thanks.
feltech
 
Posts: 2
Joined: Fri Apr 24, 2015 6:37 pm

Return to libRocket and Python


cron