威尼斯wns·8885556(vns认证网站)-BinG百科

当前位置:首页 > 新闻资讯 > 技术动向

OSG基础之内存管理

发布者:威尼斯wns·8885556    时间:2020-12-16 10:13:04

OSG是使用C++语言开发的,而该语言在动态内存管理方面做得并不好,经常需要程序员手动申请和释放内存。这种靠人工管理内存的方式不仅繁琐,而且极易造成内存泄漏,尤其在一个中大型系统中,靠人工管理内存是一项艰巨的任务。




如何解决这类问题???



数据类型osg::ref_ptr(智能指针)在源码中随处可见,它和另外一种数据类型osg::observer_ptr(观察指针)为我们提供了非常良好的动态对象使用体验。


智能指针的用法


osg::Node* pNode = new osg::Node();

osg::ref_ptrrpNode=pNode;

if(rpNode.valid())

{  

rpNode-> ...

}


通过osg::Node实例化一个智能指针模板对象rpNode,该对象可以直接保存一个使用new关键字动态创建的osg::Node对象,并可通过valid() 方法判断内部对象是否有效。


使用->操作符直接对内部对象进行调用,这里无需关心osg::Node对象的释放,因为在智能指针对象rpNode析构时会自动检查是否需要删除对象,如果需要则直接删除。


观察指针的用法


osg::Node* pNode = new osg::Node();

osg::observer_ptropNode=pNode;

if(opNode.valid())

{

opNode-> ...

}


osg::observer_ptr与osg::ref_ptr的用法基本相同,不同的是osg::observer_ptr不负责对象的释放,这也是为什么叫它观察指针的原因,可理解为只观察不管理。


所以,上面代码如果没有其他osg::ref_ptr智能指针对创建的osg::Node对象进行管理,将造成内存泄漏,该对象将不会自动释放。


实现原理


osg::ref_ptr和osg::observer_ptr是两个模板类,而用于实例化该模板类的类型必须从osg::Referenced继承。OSG中大多数类型都是从该类继承而来的,它才是实现内存自动管理的核心所在。



osg::Referenced类最主要的功能是内部维护了一个引用计数_refCount,并提供了ref()和unref()函数来负责该引用计数的递增和递减。在unref()函数中,当_refCount递减为0值时会自动释放该对象占用的内存。

    

    有了osg::Referenced类的支持,对于osg::ref_ptr而言其实只需要做两件事:


    1)在着手管理一个对象时调用该对象的ref()方法增加其引用计数;

    2)当不在管理该对象时调用该对象的unref()方法减少其引用计数



osg::observer_ptr的实现正如它的名字一样,是通过一种简单的“观察者”设计模式来实现的。osg::Referenced内部维护了一个观察者列表,并且在引用计数递减为0时主动通知所有的观察者对象,每一个osg::observer_ptr对象都是一个观察者。


    对于osg:: observer _ptr而言需要做以下三件事:


    1)在开始观察一个对象时将自己加入到该对象的观察者列表中;

    2)在停止观察对象时将自己从该对象的观察者列表中移除;

    3)收到观察者通知时,将内部观察的对象设置为无效。


关系如下

1.png


通过下表,我们来体会一下OSG中对象的创建和释放的过程,以及在这当中智能指针与观察指针的作用,引用计数的变化情况等。


2.png



每一个osg::ref_ptr对象都占有一个被引用对象的引用计数,在正常情况下只要最后一个osg::ref_ptr还在使用,被它引用的对象就不会释放。所以osg::ref_ptr可用于需要长期使用并保证一个对象可用的情况。


osg::observer_ptr 作为对象的观察者,最大的作用就是可以在访问其观察的对象时,判断该对象是否已经被销毁了。它只是尝试性的使用,不对观察对象产生任何影响,观察的对象随时可能被释放,所以应该经常使用valid()方法判断其有效性。


通过以上介绍,相信大家对OSG的智能指针和观察指针都有了一定程度的理解,并且可以在不同场景下做到正确使用。

FreeX 产品微信公众号

威尼斯wns·8885556微信公众号

威尼斯wns·8885556视频号