trivial destructor

项目中有一些地方为了得到较快的速度,使用了无需释放的简易内存分配器:先一次分配一大块内存,然后每次需要内存的时候从这块内存里面直接递增分配合适大小的内存块。当使用完这些内存了以后,不做显式的释放,直到整个大任务结束了以后,才一次释放那整块内存。这样做优点在于

  • 内存分配非常快速,仅仅递增指针即可
  • 没有释放的开销(除了整块释放)
  • 不会有碎片

这种做法是很多引擎的常见选择。但是也有一个很大的缺陷,就是每个分配对象的析构函数并没有被调用。当然我们在释放所有内存的时候也可以试图调用所有的对象的析构函数,不过出于效率考虑,很多引擎并没有在所有的模块里进行析构函数的调用,尤其是一些POD(plain old data),不调用析构函数也明显无害。当然,这样就留下了隐患。

根据墨菲定理,不想发生的事情,最终总会发生。最近项目就遇到了这样的情况。

先是大家发现有很快速的内存泄漏,不巧的是,正好引擎的内存监测系统年久失修,本来可以秒杀的问题,由于内存监测系统的罢工,导致无法被快速定位。

手工人力定位,最后发现,问题就出在我们省略的析构函数调用上。

原来,新来的同事扩展了原来的POD结构,在POD里面加上了资源分配,现在这就不是POD了,变成标准的类,顺理成章的,他也添加了析构函数,在里面释放新分配出来的资源。问题就在于,这个类型是用前述的快速分配系统创建出来的,析构函数从我们设计之初就没打算调用,这样分配的资源无法释放,造成了泄漏。

对于这样有隐患的系统,的确无法继续容忍,但我们也不打算为这样的例外牺牲效率,对所有快速分配系统调用析构函数。所以问题的核心,就变成了我们是否能够检测的这种情况了。

解决问题的想法是,我们能否检测到这个情况,如果能在编译时刻检测到这一情况,我们就可以报错,或者用模版来产生不同的代码,从而对POD沿用旧的机制,没有额外的开销,其他类则自动调用析构函数。

进一步简化问题,我们如果能确定一个类有non-trivial destructor,我们就要在释放的时候对这些对象调用析构函数。

google了一下,原来stl里面就有一个std::has_trivial_destructor,大喜,使用,果然有用,用这个模板类可以检测出一个类有没有non-trivial destructor。这样就很容易能实现编译时刻的类型检测,从而产生报警或是模版类处理析构情况。

由于项目中使用的是eastl,就原样替换成eastl的has_trivial_destructor,发现失败了。。。原来eastl只支持检测一个类型是否是pod,但是这个pod检测也不准。。。放了一个pod的struct,居然说不是pod。看了eastl代码,发现注视里面提到,考虑到跨平台的问题,说只能做到那样了。。。但是vc自带stl是可以工作的,再去看VC stl实现代码,vc的stl可读性太差了。。。都是各种宏替换。遂使用编译器预处理cpp文件,产生了一个.i文件,看了一下,里面检测non-trivial destructor的地方调用了一个__has_trivial_destructor。这个东西有意思,据我所知一般vc里面__开头的函数都是intrinsic函数。查了msdn,真是vc自己扩展的,还顺藤摸瓜,查到了其他一堆检测c++类型的intrinsic函数。

问题迎刃而解,只要用vc的扩展函数就可以搞定了。但是这东西牺牲了跨平台性,也算双刃剑。


http://www.cnblogs.com/gamedev/archive/2012/08/10/2631255.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值