Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2945414
  • 博文数量: 199
  • 博客积分: 1400
  • 博客等级: 上尉
  • 技术积分: 4126
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-06 19:06
个人简介

半个PostgreSQL DBA,热衷于数据库相关的技术。我的ppt分享https://pan.baidu.com/s/1eRQsdAa https://github.com/chenhuajun https://chenhuajun.github.io

文章分类

全部博文(199)

文章存档

2020年(5)

2019年(1)

2018年(12)

2017年(23)

2016年(43)

2015年(51)

2014年(27)

2013年(21)

2011年(1)

2010年(4)

2009年(5)

2008年(6)

分类: Java

2008-11-03 00:37:18

   Java中由于有垃圾收集器(GC)自动回收资源,所以一般情况下不需要担心内存泄漏的问题。这也是Java相对C/C++而言开发简单高效的重要原因之一。想必调试过C/C++内存泄漏障害的人都深有体会。但是如果认为Java中不存在内存泄漏也是不对的。因为GC不是万能的,也有它失灵的时候。那它什么情况下会失灵呢?先简单了解一下GC的工作方式吧。

   垃圾收集器每过一段时间就会将不再使用的资源回收。GC判断一个对象是否是不再使用的方法非常重要。它以每个活的线程对象为根检查有没有能够到达目标对象的引用链为判断标准。如果不可达则说明该对象对程序(或者线程)的执行是不可见的,因为没有任何手段可以引用该对象,自然这个对象肯定是不再被使用了。于是将其回收。

   简单思考一下,上面的判断逻辑只是“什么是不使用对象”的充分条件,而不是必要条件。至于必要条件是什么,答案只有开发者自己知道,因为只有开发者自己才能准确知道哪些对象已经确实不再需要了,GC又怎么能揣测到开发者的意图呢?

   理解了这一点我们就知道了Java内存泄漏的第一种模式:GC不能正确识别出不再使用的对象。既:存在一条以活的线程对象(通常是主线程)为起点的引用链,指向了已经不再使用的对象。并且这些对象在程序运行中未能及时释放后者数目不断增长导致内存消耗过大(如果内存消耗能始终保持在可接受的范围之内,就谈不上什么内存泄漏了)。这样的内存泄漏通常发生在一个集合对象上,尤其是作为高速缓存使用的集合对象。

   本来我以为刚才提到的模式是Java内存泄漏唯一的一种模式,但是一次实际经历使我看到了第二种Java内存泄漏的模式:GC不能正常释放它想释放的对象。这是由于用户重载了某个Java对象的finalize()方法,GC在释放这个对象时就要调用这个被修改了的finalize()方法,而这个finalize()方法又由于某个原因离奇地无法结束(比如等待某个同步对象或者发生了死循环*),也就导致这个对象没法被正常释放,于是内存泄漏自然就发生了。当然这种情况比起前面提到的第一种模式要少见的多。

* 我遇到的情况是finalize()方法在等待一个同步对象,但是该同步对象又被别的线程长时间霸占着。这个线程虽然也有释放同步对象,但这个线程循环执行并且垃圾收集的线程优先级比较低,所以释放了的同步对象很快又被它抢了去。并且这个线程在执行过程中又会创建新的修改了finalize()方法的Java对象,导致该Java对象虽然也能被释放,但释放的速度跟不上创建的数据,时间久了,内存消耗就会越来越大,内存泄漏也就发生了。
阅读(3402) | 评论(0) | 转发(0) |
0

上一篇:u-boot-1.3.4的start.S代码分析

下一篇:拖延症

给主人留下些什么吧!~~