Hello OSG users,

I am working on a project that processes large amount of data a have problems with memory leaks. Problematic part of the code does simplification of OSG subgraphs and writes out the results. In this code, no graphical window exists, it's only about reading - processing - writing of .ive files.

The code reads in two .ive files, merges the geometries in these files, does simplification on the merged geometries and writes the result to the .ive file.

On very large models the system goes out of memory in the simplification phase. There must be some memory leak in the code, I guess in the merging phase, because this is done by myself :) During the process in the single simplification step, the memory is allocated and then deallocated, but not to the same amount as before (that may be OS allocation strategy specific). When the process goes through several simplification steps, the amount of overall reserved memory increases (this is what MS Windows task manager says).

I tried to find the problem with valgrind on Linux, but it reports loss of memory in the OSG code, what is probably wrong interpretation. Does anynone use valgrind for memory leak detection in OSG apps or can you recommend other method?

I attached simplified snapshot of incremented piece of my code, if different eyes could have a short look I would highly appreciate it - maybe there is only wrong usage of readNodeFiles, merging data or osg::ref_ptr's...it seems that only small portion of the allocated memory is not deallocated.


Some messages coming from valgrind that are not clear to me (I hope OSG is memory leak free because of osg::ref_ptr ):

------------------------------------------------------------------------------------------------------------------------
==11693== 12,137 (328 direct, 11,809 indirect) bytes in 1 blocks are definitely lost in loss record 287 of 432 ==11693== at 0x4C23809: operator new(unsigned long) (vg_replace_malloc.c:230) ==11693== by 0x56B7D09: osg::Node::getOrCreateStateSet() (in /home/tomas/OpenSceneGraph-2.8.0/lib/libosg.so.2.8.0) ==11693== by 0x5EF992D: osgFX::Effect::build_dummy_node() (in /home/tomas/OpenSceneGraph-2.8.0/lib/libosgFX.so.2.8.0) ==11693== by 0x5EFA072: osgFX::Effect::Effect() (in /home/tomas/OpenSceneGraph-2.8.0/lib/libosgFX.so.2.8.0) ==11693== by 0x5EFCDDF: osgFX::Scribe::Scribe() (in /home/tomas/OpenSceneGraph-2.8.0/lib/libosgFX.so.2.8.0)
==11693==    by 0x2989BE06: ???

==11693== 17,616 (1,560 direct, 16,056 indirect) bytes in 15 blocks are definitely lost in loss record 286 of 432 ==11693== at 0x4C23809: operator new(unsigned long) (vg_replace_malloc.c:230) ==11693== by 0x6BD87C1: EdgeCollapse::addEdge(EdgeCollapse::Triangle*, EdgeCollapse::Point*, EdgeCollapse::Point*) (in /home/tomas/OpenSceneGraph-2.8.0/lib/libosgUtil.so.2.8.0) ==11693== by 0x6BDB815: EdgeCollapse::addTriangle(EdgeCollapse::Point*, EdgeCollapse::Point*, EdgeCollapse::Point*) (in /home/tomas/OpenSceneGraph-2.8.0/lib/libosgUtil.so.2.8.0) ==11693== by 0x6BDD72D: EdgeCollapse::collapseEdge(EdgeCollapse::Edge*, EdgeCollapse::Point*) (in /home/tomas/OpenSceneGraph-2.8.0/lib/libosgUtil.so.2.8.0) ==11693== by 0x6BCD03D: osgUtil::Simplifier::simplify(osg::Geometry&, std::vector<unsigned, std::allocator<unsigned> > const&) (in /home/tomas/OpenSceneGraph-2.8.0/lib/libosgUtil.so.2.8.0) ==11693== by 0x6BCD456: osgUtil::Simplifier::simplify(osg::Geometry&) (in /home/tomas/OpenSceneGraph-2.8.0/lib/libosgUtil.so.2.8.0)

-------------------------------------------------------------------------------------------------------------------------

The linux code is OSG 2.8.0, I tested the same with 2.9.7 as well.
Thank you very much for any comments and help in advance,
Tomas Hnilica



bool generateSimplifiedNodes( MyObject* node) {
/*
node is a object representing spatial region, it's 2 child nodes are more 
detailed represenations, each of 1/2 of  spatial subregion. This method created 
osg::Geode with Geomteries from the child nodes.
*/      
        osg::Group* g1 = NULL;
        osg::Group* g2 = NULL;
        /*The files read in consist of a Group with 2 children, each is a 
PagedLOD with Geode and reference to file (created here) */
        if (!node->child1()->fileName().isEmpty()) g1 = 
dynamic_cast<osg::Group*>(osgDB::readNodeFile(node->child1()->fileName()));
        if (!node->child2()->fileName().isEmpty()) g2 = 
dynamic_cast<osg::Group*>(osgDB::readNodeFile(node->child2()->fileName()));

        osg::ref_ptr<ATPGroup> resg1; /*ATPGroup is subclass of osg::Group*/
        
        osg::ref_ptr<osg::Group> g = new osg::Group();
        if (g1) {
                        osg::ref_ptr<osg::PagedLOD> pl1 = new osg::PagedLOD();
                        osg::ref_ptr<osg::Group> resg1 = new osg::Group();
                        resg1->mergeNodes(g1->node1(),g1->node2());
                        pl1->addChild(resg1);
                        QFileInfo fif(node->child1()->fileName());
                        
pl1->setDatabasePath(fif.absoluteDir().absolutePath().toStdString());
                        pl1->setFileName(1,fif.fileName().toStdString());
                        pl1->setRangeMode(osg::LOD::PIXEL_SIZE_ON_SCREEN);
                        pl1->setRange(0, 0, pixel);
                        pl1->setRange(1, pixel, 9999999999);
                        pl1->setCenter(pl1->getChild(0)->getBound().center());
                        pl1->setCullingActive(true);
                        pl1->setRadius(pl1->getChild(0)->getBound().radius());
                        g->addChild(pl1);
                }
        }
        if (g2) {
                /* ...same as for g1 ...*/
        }
        osgDB::writeNodeFile(*g.get(), fn.toStdString());
        node->setFileName(fn);
        return true;
}


bool ATPGroup::mergeNodes(osg::Group* ch1, osg::Group* ch2) {
        removeChildren(0, getNumChildren());
        osg::ref_ptr<osg::Geode> allGeode = new osg::Geode();

        osg::Geode* tempGeode;

        /*The ch1 and ch2 are always osg::Group -> osg::Switch -> osg::Geode 
(with strictly 1 osg::Geometry) */
        
        /*append all geometries from ch1 to allGeode */
        tempGeode = ch1->getChild(0);
        if (tempGeode->getDrawable(0)->asGeometry()) 
                        allGeode->addDrawable(tempGeode->getDrawable(j));
                

        /*append all geometries from ch1, if geometry with same name exists, 
merge them */
        tempGeode = ch2->getChild(0);
        if (tempGeode->getDrawable(0)->asGeometry()) 
                        /*this method is included below*/
                        appendGeometry(allGeode->getDrawable(0)->asGeometry(), 
tempGeode->getDrawable(0)->asGeometry());


        osg::Geode* g;
        osg::Geometry* srcG;
        srcG = allGeode->getDrawable(0)->asGeometry();
        /*makeScenepath is included below */
        g = makeScenePath("SIMPLIFIED_" + QString::number(_atpId) + "_" + name);

        osgUtil::Simplifier simple;
        simple.setSmoothing( false );
        simple.setSampleRatio( 0.5f );
        simple.setDoTriStrip(false);
        simple.simplify( srcG );
                        
        osg::ref_ptr<osg::Geometry> rg = new osg::Geometry();
        rg->setName(srcG->getName());
        rg->setVertexArray(srcG->getVertexArray());
        rg->setColorArray(srcG->getColorArray());
        rg->setColorBinding(osg::Geometry::BIND_OVERALL);
        rg->addPrimitiveSet(srcG->getPrimitiveSet(0) );
        rg->finalize();
        g->addDrawable(rg);
        return true;
};



void ATPGroup::appendGeometry(osg::Geometry* src, osg::Geometry* app) {
/*
Merge 2 Geometries. To have the mesh merged, the nodes must be compared by 
their positions and same position nodes should be merged into one. Otherwise 
simplification and resulting data are not ok.
*/

        osg::Vec3Array* srcNodes = 
dynamic_cast<osg::Vec3Array*>(src->getVertexArray());
        osg::Vec3Array* addNodes = 
dynamic_cast<osg::Vec3Array*>(app->getVertexArray());

        std::map<std::list<double>,int > gNodes;
        std::map<std::list<double>,std::list<int> >::iterator gNodesIt;
        std::list<double> gPos;
        std::map<int, int> conversions;

        /* insert source nodes to the map indexed by node coordinates */
        for (unsigned int j=0; j<srcNodes->size(); j++) {
                gPos.clear();
                gPos.push_back(srcNodes->at(j).x());
                gPos.push_back(srcNodes->at(j).y());
                gPos.push_back(srcNodes->at(j).z());
                gNodes[gPos]=j;
        }

        /*append destination nodes to the resulting srcNodes, search for 
duplicity and make replace map*/
        for (unsigned int j=0; j<addNodes->size(); j++) {
                gPos.clear();
                gPos.push_back(addNodes->at(j).x());
                gPos.push_back(addNodes->at(j).y());
                gPos.push_back(addNodes->at(j).z());

                if (gNodes.find(gPos)!=gNodes.end()) {
                        /*this node exists, do replacement*/
                        conversions[j] = gNodes[gPos];
                } else {
                        /*new node, append*/
                        srcNodes->push_back(addNodes->at(j));
                        conversions[j] = srcNodes->size()-1;
                }
        }

        osg::PrimitiveSet* srcPrim = 
dynamic_cast<osg::PrimitiveSet*>(src->getPrimitiveSet(0));
        osg::PrimitiveSet* addPrim = 
dynamic_cast<osg::PrimitiveSet*>(app->getPrimitiveSet(0));
        osg::ref_ptr<osg::DrawElementsUInt> resPrim = new 
osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);  

        /*add PrimitiveSet data from app*/
        for (unsigned int i = 0; i < srcPrim->getNumIndices() ; i++) {
                resPrim->push_back(srcPrim->index(i));
        }

        for (unsigned int i = 0; i < addPrim->getNumIndices() ; i++) {
                resPrim->push_back(conversions[addPrim->index(i)]);
                
        }

        gNodes.clear();
        gPos.clear();
        conversions.clear();

        src->setVertexArray(srcNodes);
        src->setPrimitiveSet(0,resPrim);
}


osg::Geode* ATPGroup::makeScenePath(const QString& cname) {
                //place switch on/off
                osg::ref_ptr<osg::Switch> compSwitch (new osg::Switch());
                compSwitch->setName(cname.toAscii());
                compSwitch->setDataVariance(osg::Object::DYNAMIC);

                //place transformation node
                osg::ref_ptr<osg::MatrixTransform> tmatrix (new 
osg::MatrixTransform(osg::Matrixd::identity()));
                compSwitch->addChild(tmatrix.get());

                //place effect node
                osg::ref_ptr<osgFX::Scribe> effect (new osgFX::Scribe());
                effect->setUpDemo();
                effect->setEnabled(false);
                tmatrix->addChild(effect.get());
                
                //place Geode
                osg::ref_ptr<osg::Geode> geode (new osg::Geode());
                geode->setName(cname.toAscii());
                effect->addChild(geode.get());

                addChild(compSwitch);
                return geode;
};
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org

Reply via email to