JVM垃圾收集策略(包含G1垃圾回收器和传统GC)

JVM垃圾回收

- jvm垃圾回收策略概述

JVM会自己选择合适的垃圾收集策略,而用户也可以自己来设置所需要的垃圾收集策略,但是就个人而言,强烈建议采用默认的垃圾收集处理机制。

垃圾的收集一定要分两个空间考虑:年轻代、老年代。老年代的内存空间要大于年轻代的内存空间,所以老年代的对象每一次执行GC都会消耗更多的时间。

这里写图片描述

同一种垃圾收集的策略,有可能会根据触发内存代的不同有不同的效果,所以先来看各个内存策略的操作特点。
新生代–串行GC,一般适用单CPU
这里写图片描述

年轻代 –并行回收GC–多CPU
这里写图片描述

也就是说,同一个GC的处理操作需要有多个线程共同完成,一个线程负责内存的扫描(扫描出所有的不用的内存对象),而另外一个线程负责对象的复制操作。
串行回收要在其间做一个短暂的暂停(线程挂起),而并行的gc回收这个暂停时间比较短,适合多CPU。但必须有暂停。

年轻代:并行GC
这里写图片描述
必须结合老年代CMS GC一起使用,并行回收GC不会这么做。

并行回收GC只是处理年轻代的,而并行GC需要与老年代GC结合。
CMS:是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度的应用上,这种GC非常合适。

老年代GC处理:

老年代串行GC:
这里写图片描述
注意:将所有存活对象集中在一端,而后将所有回收对象的内存空间整理成一块连续的内存空间。
单线程,需要暂停应用并耗时较长。

所有的串行GC处理都只是单线程处理,那么在进行处理的时候都必须暂停操作。

老年代-并行GC:
这里写图片描述

划分多个区域,一个线程一个区域。多个线程并行将多个存活对象整理在一起,并将所有被回收的对象的空间整合为一体。
与串行的处理操作相比,整体的操作只是多了一个多线程的支持,但是这样的暂停时间就会减少。但是由于老年代的空间一般比较大,所以在扫描和标记存活对象上需要花费较长时间。

老年代-并行CMS GC

这里写图片描述

这里写图片描述

优缺点:只有在第一次和重新标记阶段才会暂停整个应用,这样对应用程序所带来的影响非常小,缺点是并发标记与回收线程会争抢CPU资源,并且容易产生内存碎片。

内存越大,可能产生的垃圾越多,扫描的时间越长,成正比操作。尽量减少无用内存的产生。

- 垃圾回收策略配置

常用的GC策略:
这里写图片描述

对于JVM而言,本身有两种的运行模式:单机版客户端程序(client),服务器程序(server)–主要使用

参数配置:
这里写图片描述

参数
这里写图片描述

如果想确认使用的GC的处理,首先需要知道当前主机上可以支持的处理进程数量。(比如32进程)
范例:取得可用的进程数量。

这里写图片描述

范例:观察默认的GC处理模式:

这里写图片描述
PSYoung:
此时默认状态下,年轻代使用的是:并行回收GC(Parallel Scavenge)来进行垃圾释放。

这里写图片描述

ParOldGen
而老年代的回收使用的是“ParOldGen”,采用的是并行GC完成的老年代处理。

JVM根据电脑情况自动选择的GC策略,大部分情况,没必要去调整GC策略。

范例:使用串行GC:

这里写图片描述

范例:使用并行GC:

这里写图片描述

包含警告:
这里写图片描述

这里写图片描述

范例使用CMS处理:
只针对与并行的GC 老年代有效:
这里写图片描述

这里写图片描述

这个时候通过上面的输出可以看到CMS会经历如下几个步骤:
1.“CMS-concurrent-mark-start” : CMS标记开始
2.“CMS-concurrent-mark”:表示开始进行标记,进入到了STW(暂停)状态。
3.“CMS-concurrent-preclean-satrt”:表示预清理开始。
4.“CMS-concurrent-sweep-start”:开始进行无用对象清理

CMS的处理适当性能会好一点,但是这所有的GC策略都是现在正在常用的策略。不过似乎都有缺陷。

实际开发之中对于GC的策略不建议手工修改,默认的一般比较好用。当然只是局限于传统的GC清理处理过程。

- G1收集器

  • G1收集器简介:
    很多的GC收集策略虽然提供了,但是依然会发现这些策略总会有那么一点点的不合理,造成所有不合理的本质只有一点:内存一大,什么都废了。而且现在大内存的主机,多CPU的主机越来越多了。所以java从十多年前就已经意识到了此类问题,于是偷偷摸摸的提出了一个新的垃圾收集器(没大用起来呢)。这个收集器就是G1收集器。

这里写图片描述

虽然G1收集器是十多年前提出的概念,但是真正的出现是在jdk1.7的时候出来的(Oracle发布的)。有很多javaBUG从最初到到1.6都有,但是被Oracle收购后,jdk不断更新。
此垃圾收集器G1主要应用在多CPU以及大内存的服务器环境下。极大减少了垃圾收集的停顿时间,以提升服务器的性能。
引入目的:为了将来的某一个时间可以替换掉CMS(ConcurrentMarkSweep)收集器。但是这个刚刚出现不久,还没有被默认支持,需手动开启。

对java服务器而言,如何去选择一个合适的配置?默认情况下,java会为每一个线程分配1M的内存空间,那么如果你现在的电脑有32G的内存空间,最大可分配30G内存,那么理论上可以处理(30*1024=30720)个用户请求,真要做到这么高的访问量(每秒)上,不崩溃也快死机了。
因为网络设备、I/O设备也会占用内存。所以一般的服务器处理5000-10000基本上也就够了。(动态搭建服务器)
理论上30g不现实,因为占用太高。
一台服务器不可能内存太大。但是可以做虚拟,虚拟是个子电脑,之后再做集群。
ConcurrentHashMap:一个操作锁定,其它操作正常访问
HashTable:整个表给锁定。

G1区域划分:
这里写图片描述
在JVM启动时会自动设置这些子区域(Region)的大小,区域大小范围:1MB - 32MB,最多可以设置2048个区域,及支持的最大内存为32MB*2048 = 65536M 即64G。
JVM运行,内存越大不一定效率越高,性能越好。

此时按照G1的实现方案相当于现在将所有的子内存区域合并在了一起,也不再进行任何的区分。这样就相当于所有的内存的区域都可以按照统一的方式进行规划处理。而G1的最大特点就是避免了全内存扫描。所以G1将直接带来性能的提升。

- *G1回收策略

现在的发展:简化,太细致反而是个负担。
细致复杂配置—简化配置。

这里写图片描述

这里写图片描述

这里写图片描述

这个回收过程只针对一个内存区域。多个区域之间互不干扰和影响。

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

在整个G1进行标记和清理的时候是按照区域完成的,这样不影响其他区域的执行,除此之外,使用的形式和之前的CMS都是非常类似的操作方式。

G1相关处理参数:
如果使用G1收集器,则必须由用户自己来进行参数的指定,有如下的可用参数:
这里写图片描述

范例:使用G1收集器

这里写图片描述
整个流程明显发生了改变。

这里写图片描述

这里写图片描述

G1垃圾收集的处理性能一定要比传统的GC垃圾回收处理要高,但是G1的垃圾收集器需要用户来手动启动指派,而非默认支持的。

猜你喜欢

转载自blog.csdn.net/qq_19704045/article/details/80641031
今日推荐