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