[osg-users] How to track down memory leaks?

Wojciech Lewandowski w.p.lewandowski at gmail.com
Thu Jul 12 15:49:55 PDT 2018


Hi, Igor,

I  got interested in this problem and checked your code by converting it to
pure osgViewer. Here are my observations:

I believe you do have circular reference. Your class Scene is a callback.
So RootNode points to callback but Scene callback points to RootNode. Hence
circular ref.
However, this does not explain increased ref count of your geometries. But
I believe this issue can be explained by by lazy clearing of render bins.
RenderBins are not
cleared after Draw but before next frame Draw. So after your Update, your
geometry is Culled/Drawn and lands in RenderLeaves of RenderBin. This
RenderBin is used to draw visible geometries but its not cleared after
Draw. Its cleared later, ie on next Cull/Draw traversal when RenderLeaves
container cleared before it gets filled again. So on next Update you will
notice increased ref count because its also added to RenderLeaves
container. But the next Cull/Draw will clear RenderLeaves and your geometry
will be finally released. Here is your modified test applet code ported to
vanilla osgViewer and modified to use observer_ptr instead of ref_ptr for
RootNode. I have put breakpoint in MyGeometry Destructor to see the call
stack and the call where the geometry is actually released and that way I
found the explanation.

Cheers, hth,
Wojtek Lewandowski

czw., 12 lip 2018 o 21:49 Igor Spiridonov <igwasm at rambler.ru> napisał(a):

> Here is simple project which reproduces this issue - RefCountTest (
> https://bitbucket.org/OmegaDoom/osgrefcounttest)
>
> It's a visual studio project with qt and osg. Not sure you are using
> windows but the main code in scene.cpp. ref count checks inside
> "Scene::operator()(osg::Node* node, osg::NodeVisitor* nv)"
>
> I expect both checks to return 1 but first one returns 2 as I explained
> earlier.
>
> I suppose it's the cause of memleak. I use osg 3.2.
>
> ------------------
> Read this topic online here:
> http://forum.openscenegraph.org/viewtopic.php?p=74334#74334
>
>
>
>
>
> _______________________________________________
> osg-users mailing list
> osg-users at lists.openscenegraph.org
> http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscenegraph.org/pipermail/osg-users-openscenegraph.org/attachments/20180713/275bc44f/attachment.html>
-------------- next part --------------
#include <osg/Group>
#include <osg/Geode>
#include <osg/Texture2D>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osg/NodeCallback>
#include <osgGA/StateSetManipulator>

class Scene : public osg::NodeCallback
{
public:
  Scene();
  osg::Node* getRoot();

private:
  void operator()(osg::Node*, osg::NodeVisitor*) override;
  void UpdateScene() const;

  osg::observer_ptr<osg::Group> m_rootNode;
};

Scene::Scene()
  : m_rootNode(new osg::Group)
{
  m_rootNode->addChild(new osg::Geode);
  m_rootNode->addUpdateCallback(this);
}

osg::Node* Scene::getRoot()
{
  return m_rootNode.get();
}

void PrintDtor(int refcount)
{
  printf("Dtor Refcount: %d \n", refcount);
}

class MyGeometry : public osg::Geometry
{
public:
  ~MyGeometry()
  {
    int refcount = referenceCount();
    
    PrintDtor(refcount);
  }
};

void Scene::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
  //check refcount
  if (static_cast<osg::Geode*>(m_rootNode->getChild(0))->getNumDrawables())
  {
    auto drawable = static_cast<osg::Geode*>(m_rootNode->getChild(0))->getDrawable(0);
    int refcount = drawable->referenceCount();
    printf("Callback 1 Refcount: %d \n", refcount);
  }

  UpdateScene();

  //check refcount
  if (static_cast<osg::Geode*>(m_rootNode->getChild(0))->getNumDrawables())
  {
    auto drawable = static_cast<osg::Geode*>(m_rootNode->getChild(0))->getDrawable(0);
    int refcount = drawable->referenceCount();
    printf("Callback 2 Refcount: %d \n", refcount);
  }


  OpenThreads::Thread::microSleep(100000);
};

void Scene::UpdateScene() const
{
  auto childNode = static_cast<osg::Geode*>(m_rootNode->getChild(0));
  childNode->removeDrawables(0, childNode->getNumDrawables());

  osg::ref_ptr<osg::Geometry> geometry(new MyGeometry);
  childNode->addDrawable(geometry);

  int refcount = geometry->referenceCount();  
  printf("UpdateScene Refcount: %d \n", refcount);

}

int main(int argc, char** argv)
{
    osg::ArgumentParser arguments(&argc, argv);
    osgViewer::Viewer viewer( arguments );    

    // add the state manipulator
    viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));

    // add the thread model handler
    viewer.addEventHandler(new osgViewer::ThreadingHandler);

    // add the window size toggle handler
    viewer.addEventHandler(new osgViewer::WindowSizeHandler);

    // add the stats handler
    viewer.addEventHandler(new osgViewer::StatsHandler);

    // add the help handler
    viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));

    Scene view;
    viewer.setSceneData(view.getRoot());

    viewer.run();
}


More information about the osg-users mailing list