.NET的垃圾回收机制引发的问题
前段时间做一个C#的项目,其中一个需求是这样的:首先向一个MDB文件中写入一些数据,然后对MDB文件进行压缩,最后将MDB文件删除。在第一次完成后进行测试,发现偶尔的情况下,MDB文件没有被删除,跟踪调试下,发现程序抛出一个”其他进程正在使用该资源“的异常,导致文件不可删除。
改正这个bug 的过程是一个痛苦的过程,首先向MDB文件中写数据时,用一个OleDBConnection打开对MDB文件的连接,然后利用DataAdapter进行数据增删改的操作,最后关闭连接。整个过程是很清晰的,这样导致问题的出现非常诡异,原因基本知道,是因为数据库持有的一些资源没有被及时释放。解决这个问题分成了两个阶段,第一个阶段,把对MDB文件的操作由共享方式改为独占方式,然后分步排查是否有连接最后没有被关闭,结果发现一个,关闭后试了几次,都很正常,于是交给客户了,结果,没过几天客户反映还是不能删除,于是进入第二个痛苦的阶段,由于已经确认所有的连接都已经关闭,这样导致很难找到其他原因,后来经过思考和查找,感觉问题出在.NET的垃圾回收机制上。
由于之前没有出现过类似的问题,所以没有关注过垃圾回收,.NET的垃圾回收机制采取的是引用计数的方式,当在堆中的一个对象A,它的引用计数为0,也就是说在栈中没有任何一个变量指向它,这时对象A就被标记为可回收,但是不是立刻被释放。所以.NET的垃圾回收机制不是实时回收的,只有在内存不够的情况下,回收机制才会去释放那些被标记为可回收的对象。
这样之前的问题就可以有一个合理的解释了:虽然最后MDB的连接都关闭了,但是连接所持有的关于MDB文件的相关资源并没有被及时释放,在这种情况下,删除MDB文件自然就会出现问题。
问题最终得到了解决,解决的方法是在对MDB文件增删改的方法后,调用GC.Collect();方法,这样可以通知垃圾回收机制,马上进行一次垃圾回收。但是网上很多牛人都说基于安全性的考虑最好不要调用这个方法,我现在还不太清楚为什么会导致不安全。如果园子里有大拿知道是为什么的话,可以和我解释一下,先谢了。
改正这个bug 的过程是一个痛苦的过程,首先向MDB文件中写数据时,用一个OleDBConnection打开对MDB文件的连接,然后利用DataAdapter进行数据增删改的操作,最后关闭连接。整个过程是很清晰的,这样导致问题的出现非常诡异,原因基本知道,是因为数据库持有的一些资源没有被及时释放。解决这个问题分成了两个阶段,第一个阶段,把对MDB文件的操作由共享方式改为独占方式,然后分步排查是否有连接最后没有被关闭,结果发现一个,关闭后试了几次,都很正常,于是交给客户了,结果,没过几天客户反映还是不能删除,于是进入第二个痛苦的阶段,由于已经确认所有的连接都已经关闭,这样导致很难找到其他原因,后来经过思考和查找,感觉问题出在.NET的垃圾回收机制上。
由于之前没有出现过类似的问题,所以没有关注过垃圾回收,.NET的垃圾回收机制采取的是引用计数的方式,当在堆中的一个对象A,它的引用计数为0,也就是说在栈中没有任何一个变量指向它,这时对象A就被标记为可回收,但是不是立刻被释放。所以.NET的垃圾回收机制不是实时回收的,只有在内存不够的情况下,回收机制才会去释放那些被标记为可回收的对象。
这样之前的问题就可以有一个合理的解释了:虽然最后MDB的连接都关闭了,但是连接所持有的关于MDB文件的相关资源并没有被及时释放,在这种情况下,删除MDB文件自然就会出现问题。
问题最终得到了解决,解决的方法是在对MDB文件增删改的方法后,调用GC.Collect();方法,这样可以通知垃圾回收机制,马上进行一次垃圾回收。但是网上很多牛人都说基于安全性的考虑最好不要调用这个方法,我现在还不太清楚为什么会导致不安全。如果园子里有大拿知道是为什么的话,可以和我解释一下,先谢了。
作者:李潘
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。