System.gc();清求系统进行垃圾回收
垃圾回收器的思想是:
在一些更快的模式中,垃圾回收器并非基于引用记数技术。它们依据的思想是:对任何“活”对象,一定能最终追到其存活在堆栈或静态存储区之中的引用。这个引用链可能会穿过数个对象层次。由次, 如果从堆栈和静态存储区开始,遍历所有引用。就能够找到所有“活”对象。对应发现每个引用。必须追踪它所引用的对象。然后是此对象所包含的引用,如此反复进行。直到“根源于堆栈和静态存储区的引用”所形成的网络全部被停止访问为止。所有你访问的对象必须都是“活”的。注意,这就解决了 “交互自引用的对象组”的问题--这一种现象根本不会被发现,因此也就被自动回收了。
有一种做法是 停止-复制
1、暂停程序运行(所有它不属于后台回收模式)
2、然后将所有对象从当前堆复制到另一个堆,每本复制的对象都是垃圾对象
3、当对象复制到新堆时,它们时一个挨着一个的,所以新堆保持紧凑排列,分配内存给这些复制过来的新对象
4、把对象从一处搬到另一处时,所指向该对象的引用统统修正。位移堆或静态存储区的引用可以直接被修正。但可能还有其他指向这个对象的引用,他们在遍历的过程中才能被找到。我们可以想成一个表格,将旧地址映射到新地址。
停止-复制小总结:
该方式清理垃圾 降低效率, 这有两个原因。首先呢得有两个堆,然后又得在这两个堆之间来回捣腾。导致维护比实际需要一倍的空间。某些java虚拟机提供的解决方案是:按需从堆中分配几块较大内存,复制动作发生在这些大内存之间。
缺点:当程序稳点的时候,产生的垃圾很少甚至没有的时候
尽管如此,复制式回收器仍然会将所有内存自一处复制到另一处,这很浪费,为了避免,java虚拟机会进行检查:要是没有新垃圾产生,就会使另一种工作模式(既“自适应”)。这种模式也叫 标记-清理(mark-and-sweep),Sun公司早期版本的java使用了这种技术。对应一般用途而言,“标记-清理”方式相当慢。但是当你知道只会产生少量垃圾甚至不会产生垃圾时,它的速动就很快了。下面我们一起来看看标记-清理吧!
标记-清理
所依据的思路是从堆栈和静态存储区出发,遍历所有引用,进而在栈中找到所有存活对象,每当它找的一个存活对象,就给对象设一个标记。这个过程中不会回收任何对象。等全部标注完成时候,清理动作才开始。清理掉所有每标记的对象。释放内存并不会发生任何复制动作。所有剩下的堆空间不是连续的。垃圾回收器要是想得到连续的空间,就得重新整理剩下的对象。
上面我们所讨论的java虚拟机中,内存分配以较大的“快”为单位,如果对象够大,它会占用单独的块,严格来说,“停止复制”要求在释放旧有对象之前,必须把所有存活对象从旧堆复制到新堆。这将导致大量的内存复制行为。有了块之后,垃圾回收器在回收的时候就可以往废弃的块里面拷贝对象。每个块都用相应的代数(generation count)来记录它是否还存活。通常,如果块在某处被引用,其代数会增加。垃圾回收器将对上次回收动作之后新分配的块进行整理。这对处理大量短命的临时对象很有帮助。垃圾清理器会定期进行完整的清理动作---大型对象仍然不会被复制(只是代数增加而已),内含小型对象的那块则被复制并整理。java虚拟机会进行监视。如果所有对象都很稳定。垃圾回收器的效率顶的话,就会切换到“标记-清理”方式;同样,java虚拟机会跟踪“标记--清理”的效果,要是堆空间出现很多碎片,就会切回“停止-复制”方式。这就是“自适应”技术。你可以给它个啰嗦的称呼:“自适应的 分代的、停止-复制、标记-清理”式垃圾回收器