Java gc 垃圾回收

1、垃圾回收的区域

jvm内存区域分为线程私有和线程共享的,线程私有的包括本地方法栈、虚拟机栈、程序计数器,线程共享的主要包括方法区、堆,线程私有一般随着线程的创建、回收而回收,垃圾回收的主要区域集中在线程共享区域。

2、引用计数法和可达性分析

垃圾回收的前提需要判断哪些对象被回收,jvm有两种方案。

引用计数法:每一个对象被其他对象引用,引用次数+1,引用次数为0则需要被回收,该方案速度快,但是无法检测出循环依赖,jvm不采用该方案

可达性分析:如果从一个对象没有到达根对象的路径,或者说从根对象开始无法引用到该对象,该对象就是不可达的。这样的对象就是需要被回收的,一般而言虚拟机栈和静态引用可作为gc roots。

3、分代的垃圾回收策略

年轻代(Young Generation)

  1.所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

  2.新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。

  3.当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收

  4.新生代发生的GC也叫做Minor GC,MinorGC发生频率比较高(不一定等Eden区满了才触发)

年老代(Old Generation)

  1.在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

  2.内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。

持久代(Permanent Generation)

  用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。

4、垃圾回收算法

标记-清除算法:分为标记、清除两个阶段,标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间,优点是实现容易、速度快,缺点是容易造成内存碎片。

复制算法:将内存区域分为两块大小相等的区域,每一次使用其中的一块,垃圾回收时将存活的对象移动到另一块,将原有的那一块直接清除,不仅解决了垃圾回收,还解决了内存碎片问题,优点是效率高,不易产生碎片,缺点是费内存。

标记-整理算法:为了弥补标记-清除算法造成的内存碎片问题,标记完成之后,并不是直接清除可回收的对象,而是将存活对象想内存区域一端进行移动。

5、垃圾回收器

Serial收集器:针对新生代;使用复制算法;单线程,进行垃圾收集时,必须暂停所有工作线程,直到完成; 依然是HotSpot在Client模式下默认的新生代收集器;

ParNew收集器:Serial收集器的多线程版本,适合多CPU场景,与CMS收集器配合工作;

Parallel收集器:针对新生代;复制算法;多线程收集;以高吞吐量为目标,减少垃圾回收时间;适合后台计算任务,不适合交互过多的任务;

Serial Old收集器:Serial收集器的老年代版本;标记-整理算法;单线程;

Parallel Old收集器:Parallel收集器的老年代版本;标记-整理算法;多线程;

CMS收集器:针对老年代;标记-清除算法;并发收集;以减少停顿时间为目标,注重响应速度;初始标记、并发标记、重新标记、并发清除

G1收集器:JDK7-u4才推出商用的收集器;并行与并发;分代收集,收集范围包括新生代和老年代;结合多种垃圾收集算法,空间整合,不产生碎片;可预测的停顿:低停顿的同时实现高吞吐量;面向服务端应用,针对具有大内存、多处理器的机器;最主要的应用是为需要低GC延迟,并具有大堆的应用程序提供解决方案;初始标记、并发标记、最终标记、筛选回收;

6、相关命令

-XX:+UseSerialGC                               //使用serial垃圾回收器,新生代用Serial收集器,老年代用Serial Old收集器
-XX:+UseParNewGC                               //使用parnew收集器,新生代使用ParNew收集器,老年代使用Serial Old收集器
-XX:ParallelGCThreads                        //指定垃圾收集的线程数量,ParNew默认开启的收集线程与CPU的数量相同
-XX:+UseParallelGC                 //使用Parallel收集器,新生代使用Parallel收集器,老年代用Serial Old收集器
-XX:+UseParallelOldGC                        //新生代使用Parallel收集器,老年代使用Parallel Old收集器
-XX:MaxGCPauseMillis=value            //设置最大停顿时间
-XX:GCTimeRatio=N                             //设置垃圾收集时间占总时间的比率,0<n<100的整数;
-XX:+UseConcMarkSweepGC                    //指定使用CMS收集器;
-XX:+UseCMSCompactAtFullCollection //Full GC后,进行一次整理,整理过程是独占的,会引起停顿时间变长。仅在使用CMS收集器时生效。
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/Desktop/gc.txt  //打印gc日志

7、gc分析工具()

Gceasy:在线分析工具,https://gceasy.io/index.jsp#features(外网,最好vpn)

将gc.txt(大的话压缩一下)上传,点击分析,就可以看到分析结果

Gcplot:本地安装,本地分析

docker run -d -p 80:80 gcplot/gcplot

访问127.0.0.1/

gcviewer

下载jar包:https://github.com/chewiebug/GCViewer

java -jar gcviewer-1.36.jar

自动弹出应用程序页面,选择文件

8、gc调优

项目中没怎么遇到过,都是k8s容器部署了,jvm的设置根本轮不到我们,只能纸上谈兵,多看看博客。

博客

博客

results matching ""

    No results matching ""