`
和你在一起
  • 浏览: 677590 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JVM调优总结(四)-垃圾回收面临的问题

阅读更多

如何区分垃圾

 

    上面说到的“引用计数”法,通过统计控制生成对象和删除对象时的引用数来判断。垃圾回收程序收集计数为0的对象即可。但是这种方法无法解决循环引用。所以,后来实现的垃圾判断算法中,都是从程序运行的根节点出发,遍历整个对象引用,查找存活的对象。那么在这种方式的实现中,垃圾回收从哪儿开始的呢?即,从哪儿开始查找哪些对象是正在被当前系统使用的。上面分析的堆和栈的区别,其中栈是真正进行程序执行地方,所以要获取哪些对象正在被使用,则需要从Java栈开始。同时,一个栈是与一个线程对应的,因此,如果有多个线程的话,则必须对这些线程对应的所有的栈进行检查。

    同时,除了栈外,还有系统运行时的寄存器等,也是存储程序运行数据的。这样,以栈或寄存器中的引用为起点,我们可以找到堆中的对象,又从这些对象找到对堆中其他对象的引用,这种引用逐步扩展,最终以null引用或者基本类型结束,这样就形成了一颗以Java栈中引用所对应的对象为根节点的一颗对象树,如果栈中有多个引用,则最终会形成多颗对象树。在这些对象树上的对象,都是当前系统运行所需要的对象,不能被垃圾回收。而其他剩余对象,则可以视为无法被引用到的对象,可以被当做垃圾进行回收。

因此,垃圾回收的起点是一些根对象(java栈, 静态变量, 寄存器...)。而最简单的Java栈就是Java程序执行的main函数。这种回收方式,也是上面提到的“标记-清除”的回收方式

 

 

如何处理碎片

   由于不同Java对象存活时间是不一定的,因此,在程序运行一段时间以后,如果不进行内存整理,就会出现零散的内存碎片。碎片最直接的问题就是会导致无法分配大块的内存空间,以及程序运行效率降低。所以,在上面提到的基本垃圾回收算法中,“复制”方式和“标记-整理”方式,都可以解决碎片的问题。

 

 

如何解决同时存在的对象创建和对象回收问题

    垃圾回收线程是回收内存的,而程序运行线程则是消耗(或分配)内存的,一个回收内存,一个分配内存,从这点看,两者是矛盾的。因此,在现有的垃圾回收方式中,要进行垃圾回收前,一般都需要暂停整个应用(即:暂停内存的分配),然后进行垃圾回收,回收完成后再继续应用。这种实现方式是最直接,而且最有效的解决二者矛盾的方式。

但是这种方式有一个很明显的弊端,就是当堆空间持续增大时,垃圾回收的时间也将会相应的持续增大,对应应用暂停的时间也会相应的增大。一些对相应时间要求很高的应用,比如最大暂停时间要求是几百毫秒,那么当堆空间大于几个G时,就很有可能超过这个限制,在这种情况下,垃圾回收将会成为系统运行的一个瓶颈。为解决这种矛盾,有了并发垃圾回收算法,使用这种算法,垃圾回收线程与程序运行线程同时运行。在这种方式下,解决了暂停的问题,但是因为需要在新生成对象的同时又要回收对象,算法复杂性会大大增加,系统的处理能力也会相应降低,同时,“碎片”问题将会比较难解决。

30
2
分享到:
评论
7 楼 xuhang1128 2011-04-05  
root set的结构我还是有点疑问,也没有找到最完整的解释,不知道哪里可以找到
6 楼 wgh-23 2009-12-06  
我就保存了,呵呵……谢谢楼主!
5 楼 和你在一起 2009-11-24  
@hxy-go
谢谢~
这块我没有再深入的研究过。个人是这么理解的,root objects(也就是ZangXT说的root set)由stack、static field....等组成,在垃圾回收的时候,root objects就是起点,然后, 上面提到的那个C stack记录了所有的这些root objects。
4 楼 hxy-go 2009-11-24  
关于root objects,IBM的诊断手册上是这样说的
The first stage of tracing is the identification of root objects. The active state of the JVM is made up of the saved registers for each thread, the set of stacks that represent the threads, the statics that are in Java classes, and the set of local and global JNI references. All functions that are invoked in the JVM itself cause a frame on the C stack. This frame might contain references to objects as a result of either an assignment to a local variable, or a parameter that is sent from the caller. All these references are treated equally by the tracing routines.
因此楼主说根对象扫描从线程的栈开始是有根据的,而ZangXT 说的root set,我很了解下root set结构及存放地方,JVM是怎么维护root set的
3 楼 和你在一起 2009-11-24  
@ZangXT
谢谢!这里确实有点问题,已改正!
2 楼 ZangXT 2009-11-24  
垃圾回收的起点是root set,而不是栈。root set里面再包含栈引用,static信息等等。
所以说“垃圾回收的起点是stack”不是很合适。
1 楼 Heis 2009-11-23  
图文并茂的讲解,作入门学习和面试题来读还是挺不错的。

相关推荐

Global site tag (gtag.js) - Google Analytics