Java垃圾回收器如何工作

来源:互联网 发布:ug4.0编程刀路下载 编辑:程序博客网 时间:2024/05/22 07:54
      把对象放在了堆。

      引用计数常用来说明垃圾收集的工作方式但从未被应用于任何一种JVM中。缺陷是如果出现对象循环引用时,可能会出现对象应该被回收但引用技术不为0的情况。
      Java的垃圾回收器并非基于引用计数技术,它们依据的思想是:对任何“活”的对象,一定呢最终追溯到其存活在堆栈或静态存储区之中的引用。这个引用链条可能会穿过数个对象层次。由此,如果从堆栈和静态存储区开始遍历所有的引用,就能找到所有的“活”的对象。对于每发现的一个引用,都必须追踪它所引用的对象,然后是此对象包含的所有引用,如此反复进行,直到“根源于堆栈和静态存储区的引用”所形成的网络全部被访问为止。所有访问过的对象必须是“活”的。避免了上面说的“交互自引用的对象组”的问题。
      在这种方式下,JVM将采用一种自适应的垃圾回收技术,如何处理找到的“活”的对象取决于不同的JVM实现。(有很多中JVM实现,常用的是Sun公司的,一些公司会根据自己的需要自己实现JVM以满足自身需求)。
      有一种做法叫停止-复制(stop-and-copy),,先暂停程序的运行然后把所有存活的对象复制到另一个堆,没有被复制的全部都是垃圾。新堆里面的对象是紧凑排列的。指向这些对象的引用必须被修正。
      这种做法效率会降低,原因有两个:一是要有两个堆,要维护比实际需要多一倍的空间,某些JVM会按需从堆中分配几块较大的内存,复制动作发生在这些大块内存之间;二是程序进入稳定状态之后,可能会产生少量垃圾,甚至没有垃圾,所以复制式回收器仍然会将所有内存自一处复制到另一处,这很浪费;所以一些JVM会进行检查:要是没有新垃圾产生,就会转换到另一种工作模式标记-扫清(mark-and-sweep),在这种情况下速度会很快,所依据的思路是从堆栈和静态存储区出发,遍历所有的引用,进而找到存活的对象,每发现一个就给对象设一个标记,这个过程不会回收任何对象,只有标记工作全部完成才会开始进行清理动作,清理过程中没有被标记的对象将被释放,不会发生任何复制动作。剩下的堆空间并不连续,如果需要连续的堆空间需要重新整理剩下的对象。
      “停止-复制”垃圾回收动作发生时程序会被暂停。垃圾回收被视为低优先级的后台进程。当可用内存数量较低时,垃圾回收器会暂停运行程序,对于“标记-扫清”也是如此。
        现在讨论的JVM,内存分配以较大的“块”为单位,如果对象比较大,它会独占单独的块。有了块之后,垃圾回收器就可以往废弃的块里面拷贝对象,而不需要先把所有存活对象从旧堆复制到新堆了。每一个块都用相应的代数来记录它是否还存活。通常,如果块在某处被引用了,其代数就会增加。垃圾回收器将对上次回收动作之后新分配的块进行整理,这对处理大量短命的临时对象很有帮助。垃圾回收器会定期的进行完整的清理动作——大型对象仍然不会被复制(只是代数会增加),小型对象的那些块则会被复制并整理。JVM会进行监视,如果所有对象都很稳定,垃圾回收器效率降低的话,就切换到“标记-清扫”方式;同样,JVM会跟踪“标记-扫清”的效果,要是堆空间出现很多碎片,就会切换回“停止-复制”。
1 0
原创粉丝点击