GC与Memory pool引发的一段血案

今天坐我旁边的两个同事讨论了一个由内存管理引发的BUG,涉及到了Memery management中一些令人头疼的东东,值得说一下。
情况是这样的:我们的代码里面自己实现了一个native C++的memory pool来对某些类别的对象进行管理,而这个pool不是thread safe的。这样设计也很容易理解,一来实现一个thread safe的pool要颇费一番心血,在当时的情况下没有必要;二来,我想也是更重要的,thread safe里面大量的lock(不管选择何种同步机制)必然导致performence的严重损失,作为像memory management这样的底层工具,性能是至关重要的考虑因素。这个pool几年来一直都运行得很好,不过随着MS的.NET的引入,产品中用到了一些C++/CLI的manage code,其中很多的managed object都对native heap object进行了一对一的映射,native object的life cycle由managed object控制,简单的说就是在其constructor当中创建,finalizer当中释放(实际情况当然比这个复杂,不过不妨碍这里的讨论)。而managed object的life cycle是由GC管理的。众所周知,CLR的GC自己运行在一个独立的thread当中(要是真能这样与世无争多好啊,一声叹息...)。好,问题来了,如果一个本地对象现在被托管对象映射到,然而这个本地对象在内部又是由内存池管理,会发生什么???
因为GC运行在一个独立的线程里面,它会根据系统状况判断何时进行垃圾收集,当然一般情况下这些对我们来说都是transparent的。然而如果碰巧在内存池进行某些操作的时候GC启动了垃圾收集,一种竞争的情况就产生了(这个世界竞争还真是无处不在,想到以前做电路仿真时候大部分经历就是花在了这两个字上,SIGH~~)。比如内存池拿到了一个对象,但是在操作之前碰巧GC回收了一个托管对象,导致这个本地对象release掉,如果这个时候pool继续操作前面拿到的对象指针......结果当然就是application有了crush的机会。当然,实际中这样的可能性其实并不大,据同事说是在连续创建了10万个托管对象,逼GC造反之后才reproduce了这个bug的(大家都不容易呀,呵呵)。不过毕竟这种可能性是存在的,还是要想办法fix掉。
要从根本机制上解决这个问题并不容易。毕竟已经涉及到了最底层的memory management的东西,如果真要动pool的话那可是牵一发而动全身的大事,就不是一个bug的问题了。后来,有人提出能否在可能产生pool操作的几段code里面强制让GC先对托管对象进行回收,进而引发本地对象的释放,然后再让pool继续进行操作。这个思路貌似是可以解决我们这个BUG的。最后,我提议他们使用GC::Collect() + GC::WaitForPendingFinalizers()来进行同步...问题据说解决了,当然这也只能算一个应急的方法。
其实单就这个BUG而言,解决问题的方法远远不如分析的过程来得精彩,这也是我写本文的原因。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值