下图是对上述堆控件的垃圾回收过程。因为我们有上图可以看出,To区域是空白区,可以接受被复制的对象。由于“年轻代”易产生内存垃圾,所以采用“复制式”内存回收的方式。我们将Eden Space和From两个堆区块中的“活对象”拷贝到To区。拷贝的同时,我们也要修改被拷贝内存的栈引用地址。而对From或者Eden区域的“大对象”存储空间直接将其复制到“年老代”。因为“大对象”在From与To区多次复制的效率比较低,直接将其加入到“年老代”中以提高回收效率。
对于“年老代”的垃圾回收,就采用“标记-压缩”式垃圾回收。首先,先将活对象进行“标记”。
3、垃圾回收后的结果
下方就是“分代”垃圾回收后的具体结果。从下方简图中,我们可以看出,Eden Space和From中的活对象都被复制到了To区,而“年老代”的堆区的存储空间也变化不少。而且在“年老代”中多出了从From区复制过来的大对象。具体如下所示。
四、Eclipse的GC日志配置与分析
上面聊这么多,接下来我们来直观的感受一下在Eclipse如何查看垃圾回收的过程以及分析垃圾回收的日志信息。默认情况下,是不显示垃圾回收的过程以及打印日志的,需要在运行配置中添加相关的配置项来将垃圾回收的日志进行打印。本部分我们来看一下Eclipse中的垃圾回收日志记录的配置,然后我们来分析一下这些日志记录。当然我们本篇博客中使用的是Java8,如果你用其他版本的Java打印出来的日志信息会略有不同,好开始本部分的内容。
1、配置Eclipse的运行设置
在Eclipse中的运行设置中添加相应的配置项,垃圾回收时才会打印相应的日志信息。选择我们的工程,然后找到Run Configurations…选项,进行运行时的配置。
下方就是上述选项打开的对话框,然后找到(x)=Arguments这个标签栏,在VM arguments中添加相应的虚拟机参数,这些参数都会作为工程在运行时的参数。下方我们添加了-XX:+PrintGCTimeStamps和-XX:+PrintGCDetails两个参数。由这两个参数名我们不难看出相应参数所对应的功能,一个是打印垃圾回收时的时间戳,另一个是打印垃圾回收时的细节。当然还有好多其他的参数,比如选择“垃圾回收”时的具体算法的参数,以及选择是“串行”还是“并行”的参数,还有一些选择是“独占式”还是“并发式”垃圾回收的参数。在此就不做过多赘述了,请自行Google。
2、回收日志的打印与解析
配置完上述参数后,当我们使用System.gc(); 来进行强制垃圾回收时,会打印出相应的参数信息。首先我们得创建测试用的代码,下方就是我们所创建的测试类,当然测试类中的代码比较简单。主要就是new了以字符串,然后将引用置为null, 最后调用System.gc()进行回收。具体代码如下所示:
package com.zeluli.gclog; public class GCLogTest { main(String[] args) { String s = new String("Value"); s = null; System.gc(); } }
下方就是上述代码所运行的效果,接下来我们将对下方日志信息的主要内容进行介绍。
[PSYoungGen: 1997K->416K(38400K)] 1997K->424K(125952K), 0.0010277 secs]
[ParOldGen: 8K->328K(87552K)]
上述就是简单的垃圾回收的日志,本篇博客的内容就先到这儿吧,关于JVM中的垃圾回收的内容还有好多,以后结合着具体情况,再陆陆续续的进行介绍。今天博客就先到这儿。