查看: 8286|回复: 14

【原创】你的PagedLOD 为什么没有卸载?

[复制链接]

该用户从未签到

发表于 2012-3-17 10:15:21 | 显示全部楼层 |阅读模式
本帖最后由 fenma3422 于 2012-3-17 10:44 编辑

       分页对于大型场景而言是一个必不可少的调度渲染技术。当你发现osg自身就带有PagedLOD 功能时,何尝不兴致冲冲的立即使用。可是,在使用时突然发现只有加载没有卸载,内存随着运行不断攀升,过期的PagedLOD 节点竟然没有被osg踢出内存?苦恼啊,纠结啊?难道是bug?其实不然,osg的PagedLOD 技术已十分成熟,那么究竟是何原因造成的?焦躁的你请耐心阅读
        1、导致PagedLOD 不被卸载的第一个原因
        在使用osgViewr::Viewer::setSceneData设置场景给Viewr之前,没有把你的PagedLOD 节点加入到场景根节点下。考虑如下两种情况:
                osg::Group * root=new osg::Group;
        osg:agedLOD * lod1=new osg::PagedLOD;
        lod1->setFileName(0,"cow.osg");
        lod1->setRange(0,0,10);

        root->addChild(lod1);
        viewer->setSceneData(root /*createTeapot()*/ );

               osg::Group * root=new osg::Group;
        osg::PagedLOD * lod1=new osg::PagedLOD;
        lod1->setFileName(0,"cow.osg");
        lod1->setRange(0,0,10);

                viewer->setSceneData(root /*createTeapot()*/ );
        root->addChild(lod1);
,请回答两种情况下lod1节点都会在过期时删除吗?答案正如你所想:不是。只有第一种情况中的PagedLOD 会在过期时从内存中卸载。说起原因,就不得不告诉你一个setSceneData函数的小秘密。看下面代码:
void Scene::setSceneData(osg::Node* node)
{
    _sceneData = node;
   
    if (_databasePager.valid())
    {   
        // register any PagedLOD that need to be tracked in the scene graph
        if (node) _databasePager->registerPagedLODs(node);
    }
}
是的,在setSceneDAta时向DatabasePagerr注册了场景中的所有PagedLOD 节点,如果此时场景中还没有设置PagedLOD 节点,那么很抱歉,即使你在随后设置了,DatabasePager中注册的PagedLOD 节点依然是当时注册的那些,你随后设置的只能是计划外人口,黑户,对不起DatabasePager是不管这些黑PagedLOD 的死活。那么你可能又要问了,既然DatabasePager不管这些PagedLOD 节点的死活,那么为什么这些PagedLOD 节点可以被动态加载呢?问的好!因为PagedLOD 节点的动态加载请求是PagedLOD 节点自身发出,而卸载则是由DatabasePager管理!请查看PagedLOD 的traverse函数,它会告诉你一切。
        讲到这里,也许你已经心中有数,使用PagedLOD 节点时应该预先设置然后再setSceneData。那么你又问了如果我想在运行过程中添加PagedLOD 节点又想让其可以卸载该怎么办呢?答案就是改变时请注意调用DatabasePager::registerPagedLODs(node);函数注册户口。
         2、导致PagedLOD 节点不能卸载的第二个原因
         如果你使用PagedLOD 节点完全避免1中提到的问题,但是你的PagedLOD 节点依然顽固的赖在内存中不走,那么请你看看这里。我们知道分页的功能与内存有关,那么内存不够时PagedLOD 节点就应该自动退出内存才是,为什么他还赖在那里呢?答案是,他并不知道内存不够用了,需要你告诉他!DatabasePager::setTargetMaximumNumberOfPageLOD函数或环境变量OSG_MAX_PAGEDLOD就是干这个的。他告诉DatabasePager我的电脑内存有限只能容纳指定数量的PagedLOD ,超出这个数的过期PagedLOD 就让他滚蛋吧。也许你会问PagedLOD 个数和内存使用情况有个毛关系?确实有个毛关系,在你进行PagedLOD 分页规划时你的PagedLOD 节点的每一级都有一定的大小,那么这个大小和个数相乘就是要占用的总内存。值得一提的是osg中此数默认数量是300,( ⊙o⊙ )哇好多啊,osg觉得你的电脑配置很高!
         读到这里,你也许已经找到了原因,是的。毫无疑问osg的分页功能很强大。只是我们不懂而已,要抓紧时间了解他哟。记住,了解他,从他的内心开始,敬请阅读源码!
       

该用户从未签到

 楼主| 发表于 2012-3-17 10:23:50 | 显示全部楼层
第一次发表文章,有不到之处,敬请批评指正!

该用户从未签到

发表于 2012-3-17 10:32:03 | 显示全部楼层
多谢您的分享,支持一个~~~~~~~~~

该用户从未签到

发表于 2012-3-17 10:35:49 | 显示全部楼层
第一种情况是有点小bug的意思,不过这样设计可能是有所考虑么

该用户从未签到

 楼主| 发表于 2012-3-17 10:45:28 | 显示全部楼层
我就栽到第一种情况上面了,如果不是查看源码,打死我也想不到会有这个问题

该用户从未签到

发表于 2012-3-20 09:03:46 | 显示全部楼层
第一点的分析应该是错误的,又或者您使用的osg版本比较古老。不过总体上还是感谢您的分享!

该用户从未签到

发表于 2012-3-20 09:17:22 | 显示全部楼层
嗯 先加和后加 应该是一样的
void Scene::setSceneData(osg::Node* node)
{
    _sceneData = node;
}

看来你用的是老版本

该用户从未签到

 楼主| 发表于 2012-3-20 12:24:54 | 显示全部楼层
2.8的版本

该用户从未签到

发表于 2012-3-26 11:33:14 | 显示全部楼层
更新换代的快啊

该用户从未签到

发表于 2012-9-13 11:10:00 | 显示全部楼层
先顶后看,这问题困扰我前年了!!!

该用户从未签到

发表于 2013-11-25 10:59:34 | 显示全部楼层
您好   我也想研究下pagelod,能提供点资料吗?邮箱791521664@qq.com   不胜感激

该用户从未签到

发表于 2014-7-9 09:52:06 | 显示全部楼层
有遇到过加载pagedlod 后 堆被破坏的情况吗

该用户从未签到

发表于 2014-7-10 14:28:39 | 显示全部楼层
多谢分享,可是设置setTargetMaximumNumberOfPagedLOD后仍然出现 内存泄露的问题,这是为什么呢

该用户从未签到

发表于 2014-7-10 14:38:56 | 显示全部楼层
挺好的,继续研究源码

该用户从未签到

发表于 2014-10-10 14:37:22 | 显示全部楼层
感谢分享,初学osg
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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