JVM 垃圾回收机制
思考:简述 JVM 垃圾回收原理。
要回答 JVM 垃圾是如何回收的,就需要先理解什么是标记,也就是说,要执行垃圾回收,就需要先判断哪些对象是垃圾,哪些对象不是垃圾,这就涉及标记的问题。
所谓垃圾,也就是 Java 应用程序不再引用使用的对象,这就需要 JVM 进行垃圾回收。
JVM 通过可达性算法对整个对象进行标记,从线程栈执行的方法到 JVM 中的方法区,对引用的对象进行标记,然后再通过这些被引用的对象,再去标记哪些被这些对象不断引用的对象,进而标记出 JVM 中所有的被使用和不再被使用的对象。
针对标记的不再使用的垃圾对象,JVM 采用清理、压缩、复制三种方式进行垃圾回收。
(1)清理
直接对标记为垃圾的对象进行清理,清除掉为程序提供新的内存空间,此时,清理的结果就是内存空间有许多不连续的空间。这里的清理,并不是实际上的清空掉,而是对这些垃圾对象进行空闲标记,当有新的对象产生,需要占用空间,则 JVM 直接将这段空间给新的对象使用。
(2)压缩
不仅对垃圾对象进行清理,还对依然使用的对象空间进行压缩,使这些对象所占空间是一堆连续的内存空间,这样,被清理掉的空间也将是一堆连续的内存空间。
(3)复制
对垃圾对象进行清理之后,针对被引用的对象,进行复制,复制到一块新的内存空间,从而使得原来被使用的内存空间变成了一大块未被使用的内存空间。
对于 GC 而言,进行垃圾回收,包括串行回收器、并行回收器、并发回收器 CMS、G1 回收器。
(1)串行回收器
当发生垃圾回收时,启动线程阻塞,将所用运行线程挂起,然后启动一个新的线程用于垃圾回收,就像串行运行一样。
(2)并行回收器
当发生垃圾回收时,依然将所有运行线程阻塞挂起,启动多个垃圾回收线程同时进行 JVM 垃圾回收,也就是垃圾是由多个线程并发执行回收的。
(3)并发回收器 CMS
首先,将所有线程阻塞挂起,启动一个线程进行对象标记,也就是初始化标记,这个过程执行很快,时间很短,然后,所有被挂起的线程重新启动运行。接下来的运行过程中,会启动一个单独的线程进行标记,也就是并发标记,这个线程与所有运行线程一起执行,进而查看出初始化标记中的垃圾是否有被重新引用的。为了提高效率,所有运行的线程被挂起,同时启动多个线程进行重标记。执行结束后,所有挂起的程序再次启动运行,在这个运行过程中,继续启动一个新的线程,用于清理真正被标记为垃圾的对象,此时,被称为并发清理。这样便不会影响程序的运行,提高程序执行效率。
(4)G1 回收器
随着 JAVA 的不断升级,新的版本采用了 G1 回收器,也即是将内存空间分为多个小块的区域,不同区域具有不同的功能,而不是像之前都是一大块功能相同的连续的空间。
G1 回收器工作原理实际上与并发回收器 CMS 一样,只不过针对的空间都是不同的内存块。先初始标记、然后并发标记,再次重标记,最后并发清理。
评论