Fix growing memory consumption issues

References in simgear's cache maps prevented effects, textures, clouds,
trees and lights from being unloaded at run-time (ref-counter could never
reach 0). Changed cache maps to use OSG 'observer' pointers instead, so
reference counters aren't influenced, though cache maps still hold an
(observing) pointer. Also take care when finding a cache entry with empty
content (i.e. texture was unloaded).
This commit is contained in:
ThorstenB
2012-03-28 22:53:30 +02:00
parent a592488f3e
commit ece38a6dbf
8 changed files with 68 additions and 31 deletions
+3 -2
View File
@@ -1392,10 +1392,11 @@ public:
void valueChanged(SGPropertyNode* node) void valueChanged(SGPropertyNode* node)
{ {
_tniq->refreshValidity(); if (_tniq.valid())
_tniq->refreshValidity();
} }
protected: protected:
osg::ref_ptr<Technique> _tniq; osg::observer_ptr<Technique> _tniq;
}; };
template<typename T> template<typename T>
+2 -1
View File
@@ -24,6 +24,7 @@
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <osg/Object> #include <osg/Object>
#include <osg/observer_ptr>
#include <osgDB/ReaderWriter> #include <osgDB/ReaderWriter>
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
@@ -158,7 +159,7 @@ protected:
bool operator()(const Key& lhs, const Key& rhs) const; bool operator()(const Key& lhs, const Key& rhs) const;
}; };
}; };
typedef std::tr1::unordered_map<Key, osg::ref_ptr<Effect>, typedef std::tr1::unordered_map<Key, osg::observer_ptr<Effect>,
boost::hash<Key>, Key::EqualTo> Cache; boost::hash<Key>, Key::EqualTo> Cache;
Cache* getCache() Cache* getCache()
{ {
+12 -3
View File
@@ -279,7 +279,7 @@ public:
Texture* build(Effect* effect, Pass* pass, const SGPropertyNode*, Texture* build(Effect* effect, Pass* pass, const SGPropertyNode*,
const SGReaderWriterOptions* options); const SGReaderWriterOptions* options);
protected: protected:
typedef map<TexTuple, ref_ptr<T> > TexMap; typedef map<TexTuple, observer_ptr<T> > TexMap;
TexMap texMap; TexMap texMap;
const string _type; const string _type;
}; };
@@ -290,11 +290,20 @@ Texture* TexBuilder<T>::build(Effect* effect, Pass* pass, const SGPropertyNode*
{ {
TexTuple attrs = makeTexTuple(effect, props, options, _type); TexTuple attrs = makeTexTuple(effect, props, options, _type);
typename TexMap::iterator itr = texMap.find(attrs); typename TexMap::iterator itr = texMap.find(attrs);
if (itr != texMap.end()) if (itr != texMap.end())
return itr->second.get(); {
T* tex = itr->second.get();
if (tex)
return tex;
}
T* tex = new T; T* tex = new T;
setAttrs(attrs, tex, options); setAttrs(attrs, tex, options);
texMap.insert(make_pair(attrs, tex)); if (itr == texMap.end())
texMap.insert(make_pair(attrs, tex));
else
itr->second = tex; // update existing, but empty observer
return tex; return tex;
} }
+12 -5
View File
@@ -44,7 +44,7 @@ using namespace osg;
using namespace effect; using namespace effect;
typedef vector<const SGPropertyNode*> RawPropVector; typedef vector<const SGPropertyNode*> RawPropVector;
typedef map<const string, ref_ptr<Effect> > EffectMap; typedef map<const string, observer_ptr<Effect> > EffectMap;
namespace namespace
{ {
@@ -122,7 +122,8 @@ Effect* makeEffect(const string& name,
{ {
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex); OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
EffectMap::iterator itr = effectMap.find(name); EffectMap::iterator itr = effectMap.find(name);
if (itr != effectMap.end()) if ((itr != effectMap.end())&&
itr->second.valid())
return itr->second.get(); return itr->second.get();
} }
string effectFileName(name); string effectFileName(name);
@@ -207,7 +208,8 @@ Effect* makeEffect(SGPropertyNode* prop,
itr = cache->find(key); itr = cache->find(key);
if (itr != cache->end()) { if (itr != cache->end()) {
effect = itr->second.get(); effect = itr->second.get();
effect->generator = parent->generator; // Copy the generators if (effect.valid())
effect->generator = parent->generator; // Copy the generators
} }
} }
if (!effect.valid()) { if (!effect.valid()) {
@@ -219,8 +221,13 @@ Effect* makeEffect(SGPropertyNode* prop,
lock(effectMutex); lock(effectMutex);
pair<Effect::Cache::iterator, bool> irslt pair<Effect::Cache::iterator, bool> irslt
= cache->insert(make_pair(key, effect)); = cache->insert(make_pair(key, effect));
if (!irslt.second) if (!irslt.second) {
effect = irslt.first->second; ref_ptr<Effect> old = irslt.first->second.get();
if (old.valid())
effect = old; // Another thread beat us in creating it! Discard our own...
else
irslt.first->second = effect; // update existing, but empty observer
}
effect->generator = parent->generator; // Copy the generators effect->generator = parent->generator; // Copy the generators
} }
} else { } else {
+16 -6
View File
@@ -64,7 +64,7 @@ using namespace std;
namespace namespace
{ {
typedef std::map<std::string, osg::ref_ptr<Effect> > EffectMap; typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
EffectMap effectMap; EffectMap effectMap;
} }
@@ -102,7 +102,13 @@ SGNewCloud::SGNewCloud(const SGPath &texture_root, const SGPropertyNode *cld_def
// Create a new Effect for the texture, if required. // Create a new Effect for the texture, if required.
EffectMap::iterator iter = effectMap.find(texture); EffectMap::iterator iter = effectMap.find(texture);
if (iter == effectMap.end()) {
if (iter != effectMap.end()) {
effect = iter->second.get();
}
if (!effect.valid())
{
SGPropertyNode_ptr pcloudEffect = new SGPropertyNode; SGPropertyNode_ptr pcloudEffect = new SGPropertyNode;
makeChild(pcloudEffect, "inherits-from")->setValue("Effects/cloud"); makeChild(pcloudEffect, "inherits-from")->setValue("Effects/cloud");
setValue(makeChild(makeChild(makeChild(pcloudEffect, "parameters"), setValue(makeChild(makeChild(makeChild(pcloudEffect, "parameters"),
@@ -111,10 +117,14 @@ SGNewCloud::SGNewCloud(const SGPath &texture_root, const SGPropertyNode *cld_def
texture); texture);
ref_ptr<SGReaderWriterOptions> options; ref_ptr<SGReaderWriterOptions> options;
options = SGReaderWriterOptions::fromPath(texture_root.str()); options = SGReaderWriterOptions::fromPath(texture_root.str());
if ((effect = makeEffect(pcloudEffect, true, options.get()))) effect = makeEffect(pcloudEffect, true, options.get());
effectMap.insert(EffectMap::value_type(texture, effect)); if (effect.valid())
} else { {
effect = iter->second.get(); if (iter == effectMap.end())
effectMap.insert(EffectMap::value_type(texture, effect));
else
iter->second = effect; // update existing, but empty observer
}
} }
} }
+1 -2
View File
@@ -84,7 +84,7 @@ private:
// The density of the cloud is the shading applied // The density of the cloud is the shading applied
// to cloud sprites on the opposite side of the cloud // to cloud sprites on the opposite side of the cloud
// from the sun. For an invidual cloud instance a value // from the sun. For an individual cloud instance a value
// between min_density and max_density is chosen. // between min_density and max_density is chosen.
float min_density; float min_density;
float max_density; float max_density;
@@ -102,7 +102,6 @@ private:
static float sprite_density; static float sprite_density;
osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y); osg::Geometry* createOrthQuad(float w, float h, int varieties_x, int varieties_y);
}; };
+12 -6
View File
@@ -208,7 +208,7 @@ void addTreeToLeafGeode(Geode* geode, const SGVec3f& p)
} }
} }
typedef std::map<std::string, osg::ref_ptr<Effect> > EffectMap; typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
static EffectMap treeEffectMap; static EffectMap treeEffectMap;
@@ -299,9 +299,14 @@ osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform
for (i = forestList.begin(); i != forestList.end(); ++i) { for (i = forestList.begin(); i != forestList.end(); ++i) {
TreeBin* forest = *i; TreeBin* forest = *i;
Effect* effect = 0; ref_ptr<Effect> effect;
EffectMap::iterator iter = treeEffectMap.find(forest->texture); EffectMap::iterator iter = treeEffectMap.find(forest->texture);
if (iter == treeEffectMap.end()) {
if (iter != treeEffectMap.end())
effect = iter->second.get();
if (!effect.valid())
{
SGPropertyNode_ptr effectProp = new SGPropertyNode; SGPropertyNode_ptr effectProp = new SGPropertyNode;
makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree"); makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree");
SGPropertyNode* params = makeChild(effectProp, "parameters"); SGPropertyNode* params = makeChild(effectProp, "parameters");
@@ -309,9 +314,10 @@ osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform
params->getChild("texture", 0, true)->getChild("image", 0, true) params->getChild("texture", 0, true)->getChild("image", 0, true)
->setStringValue(forest->texture); ->setStringValue(forest->texture);
effect = makeEffect(effectProp, true, options); effect = makeEffect(effectProp, true, options);
treeEffectMap.insert(EffectMap::value_type(forest->texture, effect)); if (iter == treeEffectMap.end())
} else { treeEffectMap.insert(EffectMap::value_type(forest->texture, effect));
effect = iter->second.get(); else
iter->second = effect; // update existing, but empty observer
} }
// Now, create a quadtree for the forest. // Now, create a quadtree for the forest.
+9 -5
View File
@@ -159,7 +159,7 @@ gen_standard_light_sprite(void)
namespace namespace
{ {
typedef boost::tuple<float, osg::Vec3, float, float, bool> PointParams; typedef boost::tuple<float, osg::Vec3, float, float, bool> PointParams;
typedef std::map<PointParams, ref_ptr<Effect> > EffectMap; typedef std::map<PointParams, observer_ptr<Effect> > EffectMap;
EffectMap effectMap; EffectMap effectMap;
@@ -174,7 +174,8 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
PointParams pointParams(size, attenuation, minSize, maxSize, directional); PointParams pointParams(size, attenuation, minSize, maxSize, directional);
ScopedLock<Mutex> lock(lightMutex); ScopedLock<Mutex> lock(lightMutex);
EffectMap::iterator eitr = effectMap.find(pointParams); EffectMap::iterator eitr = effectMap.find(pointParams);
if (eitr != effectMap.end()) if ((eitr != effectMap.end())&&
eitr->second.valid())
return eitr->second.get(); return eitr->second.get();
// Basic stuff; no sprite or attenuation support // Basic stuff; no sprite or attenuation support
Pass *basicPass = new Pass; Pass *basicPass = new Pass;
@@ -204,7 +205,7 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
spritePass->setTextureAttribute(0, attrFact->getStandardTexEnv()); spritePass->setTextureAttribute(0, attrFact->getStandardTexEnv());
Pass *combinedPass = clone(spritePass, CopyOp::SHALLOW_COPY); Pass *combinedPass = clone(spritePass, CopyOp::SHALLOW_COPY);
combinedPass->setAttributeAndModes(point); combinedPass->setAttributeAndModes(point);
Effect* effect = new Effect; ref_ptr<Effect> effect = new Effect;
std::vector<std::string> parameterExtensions; std::vector<std::string> parameterExtensions;
if (SGSceneFeatures::instance()->getEnablePointSpriteLights()) if (SGSceneFeatures::instance()->getEnablePointSpriteLights())
@@ -232,8 +233,11 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
Technique* basicTniq = new Technique(true); Technique* basicTniq = new Technique(true);
basicTniq->passes.push_back(basicPass); basicTniq->passes.push_back(basicPass);
effect->techniques.push_back(basicTniq); effect->techniques.push_back(basicTniq);
effectMap.insert(std::make_pair(pointParams, effect)); if (eitr == effectMap.end())
return effect; effectMap.insert(std::make_pair(pointParams, effect));
else
eitr->second = effect; // update existing, but empty observer
return effect.release();
} }