查看: 3806|回复: 9

OSG中内存跟踪的疑问

[复制链接]

该用户从未签到

发表于 2008-3-31 09:42:25 | 显示全部楼层 |阅读模式
在OSG中使用ref_ptr可以很好跟踪内存, 是因为在ref_ptr的destructor里面有下面语句:
  1. ~ref_ptr() { if (_ptr) _ptr->unref();  _ptr = 0; }
复制代码
而且Referenced类的析构函数设为protectd,导致所有的派生类不能定义在栈上面:
  1. Node node;//错误
复制代码
而必须定义在堆上面:
  1. Node node*=new Node();
复制代码
但是问题就来了:
  1. osg::Node* node= new osg::Node();
  2. delete node;
复制代码
很明显delete node是错误的,~Node()是受保护的,但是此时OSG是如何跟踪以及释放申请的这个Node指针的?
顺便帮忙解释一下ObserveSet类的作用?
谢谢指教。

该用户从未签到

发表于 2008-3-31 10:06:05 | 显示全部楼层
首先,智能指针ref_ptr的作用就在于不必手动delete node,当引用内存计数值_refCount到达0时,系统会自动释放它所对应的Node或者其它Referenced派生对象。
_refCount数值的增加或者减少由函数ref()和unref()执行,在unref函数中同时还执行_refCount>0的判断,当引用计数值为0时,将简单地执行:
  1. if (needDelete)
  2. {
  3.     if (getDeleteHandler()) deleteUsingDeleteHandler();
  4.     else delete this;    // 这一行代替我们执行了内存释放的工作
  5. }
复制代码
可以暂时不用考虑getDeleteHandler的问题,它是内部渲染对象所用的类,OSG的内部渲染对象通常不使用ref_ptr而是DeleteHandler来执行内存管理的工作,以提高效率

至于ObserveSet类,这个是什么~~我在2.3.4的文档里没有发现这个类?

该用户从未签到

 楼主| 发表于 2008-3-31 12:20:46 | 显示全部楼层
谢谢array的回复;
我的意思是说,不使用ref_ptr,只是简单地:
  1. osg::Node node= new  osg::Node();
复制代码
但是此时OSG中怎么去释放node 这个指针呢?
显式的delete是肯定不可以的。

该用户从未签到

发表于 2008-3-31 13:12:33 | 显示全部楼层
原帖由 dizuo 于 2008-3-31 12:20 发表
谢谢array的回复;
我的意思是说,不使用ref_ptr,只是简单地:osg::Node node= new  osg::Node();但是此时OSG中怎么去释放node 这个指针呢?
显式的delete是肯定不可以的。


如果必须手动释放内存的话,似乎除了ref_ptr也没有别的方法
系统退出的时候会自动析构所有的类并释放每一个类成员,因此在main函数中定义一个Node* node是不用考虑释放问题的;如果这个node指针是在某个被反复调用的函数中执行新内存分配的工作,那么建议你使用ref_ptr,否则可能会产生内存泄漏的问题。

该用户从未签到

 楼主| 发表于 2008-4-1 12:30:16 | 显示全部楼层
  1. #include <iostream>
  2. #include <windows.h>
  3. #include <crtdbg.h>
  4. #include <malloc.h>

  5. using std::endl;

  6. osg::ref_ptr<osg::Node> createSceneGraph();

  7. int
  8. main( int argc, char** argv )
  9. {
  10.         int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); //为了跟踪检测;
  11.         tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
  12.         _CrtSetDbgFlag( tmpFlag );

  13.         osg::Node* node1=new osg::Node();
  14.         osg::Node* node2=new osg::Node();

  15.         return 0;
  16. }
复制代码
上面我做了一个测试;没有delete,也不能delete;调试的时候,当推出main函数,就检测到内存泄漏:
  1. Detected memory leaks!
  2. Dumping objects ->
  3. {777} normal block at 0x00E65AD8, 24 bytes long.
  4. Data: <                > 20 AC 15 00 FF FF FF FF 00 00 00 00 00 00 00 00
  5. {776} normal block at 0x00E65A90, 8 bytes long.
  6. Data: <  =  Z  > 9C FB 3D 10 D8 5A E6 00
  7. {775} normal block at 0x00E659A0, 176 bytes long.
  8. Data: <  B  Z          > 94 87 42 00 90 5A E6 00 00 00 00 00 00 00 00 00
  9. {774} normal block at 0x00E65948, 24 bytes long.
  10. Data: <                > E8 AB 15 00 FF FF FF FF 00 00 00 00 00 00 00 00
  11. {773} normal block at 0x003EB530, 8 bytes long.
  12. Data: <  = HY  > 9C FB 3D 10 48 59 E6 00
  13. {772} normal block at 0x00E65858, 176 bytes long.
  14. Data: <  B 0 >         > 94 87 42 00 30 B5 3E 00 00 00 00 00 00 00 00 00
  15. Object dump complete.
复制代码

该用户从未签到

 楼主| 发表于 2008-4-1 12:36:54 | 显示全部楼层
可见在OSG中,因为Referenced类的整个继承体系里面的析构函数都是protected,这就导致所有派生类的实例不能定义在栈上面,只能够通过new定义在堆上面,而且必须使用ref_ptr。
大家是怎么看的?

该用户从未签到

发表于 2008-4-1 16:54:39 | 显示全部楼层
原帖由 dizuo 于 2008-4-1 12:36 发表
可见在OSG中,因为Referenced类的整个继承体系里面的析构函数都是protected,这就导致所有派生类的实例不能定义在栈上面,只能够通过new定义在堆上面,而且必须使用ref_ptr。
大家是怎么看的?


呵呵,上述分析基本上看来是正确的,佩服佩服。
不过我想,一般来说这几个问题对程序本身不会有太多影响:使用new来分配节点对象是一种很常见的方法,例如Qt分配UI元素也采用了相同的方法;如果定义节点时可以定义在栈上的话,恐怕往往会遇到局部变量被自动释放以致渲染出错的问题,这也是我们很难检查的
至于是否使用ref_ptr,个人认为还是见仁见智的,当然节点对象在分配内存时最好还是使用ref_ptr,然后在其它需要引用这个对象的地方就可以直接引用指针了。主函数退出时检查到的内存泄漏会由操作系统负责释放,通常不用太担心~~

该用户从未签到

 楼主| 发表于 2008-4-1 18:34:14 | 显示全部楼层
恩,是这样子,
OSG中的对内存的跟踪机制确实很高明,以至于用户根本不需要担心这种问题,不过对于有些程序员来说,反而有点不习惯了。

该用户从未签到

发表于 2008-4-6 21:19:27 | 显示全部楼层
其实node如果被new了之后
一般来说是要被加载到场景里面的

比如root->addchild(node);
或者viewer.setScenedata(node);

这样node已经被root或者viewer里面的ref_ptr进行管理,只要viewer定义为栈内的对象,在程序退出时都可以无内存泄漏,而不用显式地使用ref_ptr

该用户从未签到

发表于 2010-7-13 10:42:33 | 显示全部楼层
本帖最后由 whusunny 于 2010-7-13 10:45 编辑

楼上说的不错,但是这样只能保证程序退出时没有内存泄露,程序运行时的内存泄露问题仍然存在。看来还是需要智能指针,或者程序员自己负责。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表