1.垃圾回收
垃圾回收机制有很多种,比如引用计数,标记-清扫,停止-复制,分代回收等。下面一一说明。
1.1 引用计数
即每当一个对象增加一个引用时,其引用计数就加一,当引用离开其作用域,该对象的引用计数标志就减一,直到该标志位0时,就清理。
从上面我们可看出如下几个问题:1.这种垃圾回收程序会一直运行在程序中遍历监听堆里面对象列表的引用计数变化情况,无疑这会造成极大的开销。2.最为关键的是它无法处理循环引用的情况。
所以实际上引用计数方式从未在Java垃圾回收技术上应用过。
1.2 标记-清扫/停止-复制
- 标记-清扫:
这种方式就并非根据引用计数的思想,而是通过遍历栈区中的引用,找到所有存活的对象,并标记它。而没标记的对象则是将会被清理的对象。这样就不会出现循环引用无法清理的情况了。
思考一下,这也会有一些其他问题,就是虽然释放了那些内存空间,但是在不断的清理分配下,就会产生碎片问题。这样虽然表面上空间足够,但是有可能并没有足够大的连续空间给新对象使用。所以下面的停止-复制就是用来解决这种情况的。 - 停止-复制:
顾名思义,这种方式下,用户运行的程序将会暂停,把碎片内存从新整理成连续空间。
但是其中,如何整理便是一个较大的问题,显然直接把所有碎片依次重新复制到一个新的连续堆空间上去将会消耗大量的时间。而且也不应该每次标记-清扫之后都要进行整理,只需要连续内存空间不足时才进行整理。所以后面才引入了分代回收机制。
1.3 分代回收
在上面的基础上,JVM对内存空间的整理实际上是按下面这种方式执行的。
JVM中将内存按较大的块为单位进行分配,对于一些大型对象,他可能占据一整个块。每个块都有相应的代数来记录它存活的时间长短。如果它历经几次垃圾回收都仍然存活,说明它在下一次被清理的概率也很小,所以垃圾回收器会优先清理代数低的块,这对处理大量短命的临时对象很有帮助。另外对于包含大型对象的块不会被复制,只是其代数会增加,而那些内含小型对象的块则会经常被整理。
另外提一下垃圾回收的自适应模式,即JVM会进行监视,如果所有对象都很稳定,垃圾回收器的“停止-复制”方式效率降低,就会切换到“标记-清扫”方式。同样JVM也会监视“标记-清扫”的效果,如果,产生的内存碎片过多的话又会切换到“停止-复制”模式。
2. JIT技术
简单来讲,就是Java编译器对于生成的.class文件并不会一次性把所有代码都编译成机器码,而是在必要时才会编译代码。具体细节可参考《深入理解 Java 虚拟机》。