Jvm垃圾回收——第二章

上文简单介绍了JVM的一些原理作为铺垫,接下来介绍一下垃圾回收。

java的垃圾回收机制,主要采用的是分代回收机制。

分为:

1)新生代:新出生的对象在这里创建,又分为一个eden(伊甸园,这个名字很贴切),两个survivor区。

刚刚出生的小baby,当然放在eden,

2)旧生代:因为在新生代活的较长,在若干次内存回收后进入这,作为生命周期较长的对象。

3)持久代:主要是类二进制字节码,放在方法区。

以上三个地方就是内存回收进行的主要场地。

为什么采用这种方式呢?

我有一些自己的看法,对整块堆内存进行全盘的垃圾回收是很耗费资源滴~ 因为往往需要让应用程序停下来,各种清除啊,复制啊,压缩啊,造成应用程序停顿,外界看起来就是程序进入了卡巴斯基模式。

分代回收机制的思想尽量避免全盘GC,分成几个区分别放不同生命周期的对象。比如新生代就是放生命周期短的对象,这块我可以整天GC,然后把很久都不死的对象放入旧生代,where will not GC so frequently.这是我的一点见解,欢迎吐槽。


JVM调优,主要是两个方面需要考虑

1)大小:这些场地的大小

-Xmx 堆内存最大可用内存

-Xms 堆内存初始内存大小

-Xss 线程的堆栈大小

-XX:MaxPermSize 最大持久代大小

-XX:PermSize大小

-XX:NewRatio 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)

-XX:SurvivorRatio Eden区与Survivor区的大小比值


2)算法:回收收集器最合适方式的选择

针对新生代和旧生代,又有不同的两套算法。

A、新生代垃圾收集器

1、Serial收集器

特点,单线程工作方式,暂停工作线程直到垃圾回收结束。

2、ParNew收集器

特点,多线程工作方式,也会暂停工作线程,但是在多CPU机器上相对于1能缩短回收时间。

3、Parallel收集器

特点,多线程工作方式,跟工作线程并行工作,追求高吞吐率。

用Parallel收集器是一种怎么样的体验?它关注的是提高jvm的吞吐率,就是CPU有效运行时间/CPU中运行时间。

在吞吐率很高的系统中,比如运行100分钟,可能有1秒钟系统上厕所去了,导致用户等待了1秒,哈哈哈哈。

此收集器只在新生代采用多线程,而下面介绍的CMS虽然也是多线程工作但那是在老生代工作。

-XX:+UseParallelGC或-XX:+UseParallelOldGC

缺点是会暂停工作线程,当堆越大,暂停的时间就越长。


B、老生代垃圾回收器

1、Serial Old

作为上面在老生代的对应,其实很少用到。

2、Parallel Old

-XX:+UseParallelOldGC

使用一下代码运行,看并行回收器是如何工作的。

-XX:+PrintGCDetails -Xmx100M -Xms100M -XX:+UseParallelOldGC -XX:ParallelGCThreads=8

public class BasicThreadTest extends Thread {
	
	static int m = 1024 * 1024;
	
	public static void main(String[] args) {
		
		BasicThreadTest b1 = new BasicThreadTest("Thread a");
		BasicThreadTest b2 = new BasicThreadTest("Thread b");
		
		b1.setName("BasicThreadTest-1");
		b2.setName("BasicThreadTest-2");
		
		b1.start();
		b2.start();
	}
	
	public BasicThreadTest(String name) {
		
	}
	
	@Override
	public void run() {
		while (true) {
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			byte[] a = new byte[2 * m];
		}
	}

}


Jvm垃圾回收——第二章_第1张图片

Jvm垃圾回收——第二章_第2张图片

分析:堆的占用率呈现锯齿状分布。


3、CMS收集器(重点)

-XX:+UseConcMarkSweepGC

特点,与工作线程并行运行,因此造成的停顿很短咯,系统的相应时间更快。

那时什么样的体验呢?

点开网页,一下子唰唰唰的就出来了。因此适合用在Web系统。

缺点也是有的,比如:

1)与工作线程争夺CPU,导致吞吐率降低。

2)如果浮动垃圾太多,造成内存不够(Concurrent Mode Failure),就会触发一次Serial Old的full GC,停顿就很长很长。浮动垃圾的产生是因为工作线程与GC线程同时运行,GC线程刚刚完成标记,就产生了新的垃圾,而这部分垃圾只能等下一次标记。这部分未标记的垃圾就不能再本次GC中回收。

-XX:CMSInitiatingOccupancyFraction

3)CMS基于标记-清除的方式会导致大量的内存碎片,对与分配大对象就显得很麻烦,可能不得不做一次full GC来腾出足够空间。

解决方案:

-XX:UseCMSCompactAtFullCollection 让每次FGC之后整理内存,合并碎片。

-XX:CMSFullGCBeforeCompaction 比上面人性化一点,设置每隔几次FGC才压缩一次。


-XX:+PrintGCDetails -Xmx100M -Xms100M -XX:+UseConcMarkSweepGC

Jvm垃圾回收——第二章_第3张图片

Jvm垃圾回收——第二章_第4张图片

分析:内存使用率始终在低水平。CPU占用率也不高。


Jvm垃圾回收——第二章_第5张图片




你可能感兴趣的:(Jvm垃圾回收——第二章)