一.在JVM中什么是垃圾?如何判断一个对象是否可被回收?哪些对象可以作为GC Roots的根

  垃圾就是在内存中已经不再被使用到的空间就是垃圾.

  1.引用计数法:

    内部使用一个计数器,当有对象被引用+1,没有就-1,但是没有办法解决循环引用的问题,JVM不采用此类回收法

  2.枚举根节点可达性分析(GC Root) 它必须是一组活跃的引用

    思路:通过一系列名为GC Roots的对象作为起始点,从这个被称为GC Root的对象开始向下进行搜索,如果一个对象达到GC Roots

       没有任何的引用链相连时,这说明此对象不可用,也即给定一个集合的引用作为根出发,通过引用关系遍历对象图,能被遍历到

       的对象就判定为存活,没有遍历到的就判定为死亡

  3.

    1.虚拟机栈,栈帧中的局部变量区,也称为局部变量表中引用的对象

    2.方法区中的类静态属性所引用的对象

    3.方法区中常量引用的对象

    4.本地方法栈中JNI(native方法)所引用的对象

二.如何查看服务器JVM参数的默认值,如何查看正在运行的Java程序的参数?JVM中的常用参数有哪些?可否举例说明

  1.分为三种参数类型

    标配参数(-version,-help,-showversion)

    X参数(-Xint 解释执行,-Xcomp 第一次使用就编译成本地代码,-Xmixed 混合模式)

    XX参数

      布尔值类型 -XX:+/- 某个属性值 (+表示开启,-表示关闭)

      键值对类型 -XX:某个参数 = 某个值

  2.分为两个步骤

    jps -l  查看到正在运行的Java程序的PID

    jinfo -flag -具体参数 PID 查看当前正在运行的Java程序的当前参数的信息

    jinfo -flags PID 查看当前正在运行的Java程序的所有配置信息

  3.

    boolean类型的参数

      PrintGCDetails 是否打印GC的细节

      UseSerialGC 是否使用串行垃圾回收器

    key-value类型参数

      MetaSpaceSize 设置元空间的大小

      MaxTenuringThreshould 设置新生代对象经过多少次可以晋升到老年代

    查看默认的参数

      java -XX:+PrintFlagsInitial -verion 查看Java虚拟机在出厂时候的参数配置

     其中 =  表示值是多少/是否开启对应功能 := 表示已经被JVM获取手动修改过的参数

      java -XX:+PrintCommandLineFlags 查看JVM默认的GC算法,jdk1.8 默认server端使用的是串行GC,在1.10之后统一使用G1垃圾收集器

    常用参数配置

      -Xms 设置初始堆内存大小,默认为主物理内存的1/64 等价于 -XX:InitialHeapSize

      -Xmx 设置堆的最大分配内存,默认为主物理内存的1/4,等价于 -XX:MaxHeapSize

      -Xss  设置单个线程的栈的大小,一般默认为512k-1024k,取决于操作系统,Linux/Unix默认为1024k,Windows根据虚拟内存大小来决定,默认出厂值为0

         等价于 -XX:ThreadStackSize 

      -Xmn 设置年轻代的大小,一般不用更改

      -XX:MetaSpaceSize 设置元空间的大小,元空间的本质和永久代类似,都是对JVM中方法区的实现,二者的区别在于,元空间并不在虚拟机中,使用的是本地

                的主物理内存,因此在默认情况下,元空间的大小仅受本地内存空间的限制

      -XX:PrintGCDetails 打印出GC收集的详细日志信息

      -XX:SurvivorRatio 设置Eden区的比例占多少,S0/S1相同

      -XX:NewRatio 设置年轻代和老年代在堆解构的占比

              -XX:NewRatio=2 新生代占1,老年代占2,年轻代占整个堆的1/3

               -XX:NewRatio=4 新生代占1,老年代占4,年轻代占整个堆的1/5

      -XX:MaxTenuringThreshould 设置新生代对象经过多少次可以晋升到老年代,默认是15次

     典型配置案例

     -Xms128m -Xmx4096m -Xss1024k -XX:MetaspaceSize=512m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseSerialGC

public static void show01(){
System.out.println("****** hello GC ******");
// byte[] byteArr = new byte[50*1024*1024]; try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

  修改前的参数

    -XX:InitialHeapSize=265650752

    -XX:MaxHeapSize=4250412032

    -XX:+PrintCommandLineFlags

    -XX:+PrintGCDetails

    -XX:+UseCompressedClassPointers

    -XX:+UseCompressedOops

    -XX:-UseLargePagesIndividualAllocation

    -XX:+UseParallelGC

  修改后的参数

    -XX:InitialHeapSize=134217728

      -XX:MaxHeapSize=4294967296

   -XX:MetaspaceSize=536870912

    -XX:+PrintCommandLineFlags

    -XX:+PrintGCDetails

    -XX:ThreadStackSize=1024

    -XX:+UseCompressedClassPointers

    -XX:+UseCompressedOops

    -XX:-UseLargePagesIndividualAllocation

    -XX:+UseSerialGC

  打印的GC的日志收集信息 规律: [名称: GC前内存占用 -> GC后内存占用(该区内存总大小)]

  配置:   -Xms10m -Xmx10m -XX:+PrintGCDetails

GC
[PSYoungGen: 1366K->496K(2560K)] 1366K->520K(9728K), 0.0005838 secs][Times: user=0.00 sys=0.00, real=0.00 secs]
YoungGC前新生代占用 YoungGC前堆内存占用 YoungGC耗时 YoungGC用户耗时 系统耗时 实际耗时
YoungGC后新生代占用 YoungGC后堆内存占用
新生代总大小 JVM堆总大小
FULL GC
[PSYoungGen: 464K->0K(2560K)] [ParOldGen: 24K->357K(7168K)] 488K->357K(9728K), [Metaspace: 3075K->3075K(1056768K)], 0.0030993 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Young区 GC前Young区内存占用 Old区 GC前Old区内存占用 GC前堆内存占用 元空间 GC前内存占用 GC耗时 用户时间 系统时间 实际时间
GC后Young区内存占用 GC后Old区内存占用 GC后堆内存占用 GC后内存占用
Young区总大小 Old总大小 JVM堆总大小 元空间总大小

四.常用的GC算法有哪些?可否谈一谈都有垃圾回收器/垃圾回收算法?分别适用于哪些场景?可否详细的说一下为什么从1.10开始都默认采用G1收集器,谈谈你的见解?

  1.常用的GC算法有4种

    引用计数/复制/标记整理/标记清除

  2.有4种垃圾收集器

    1.串行垃圾收集器

      它是单线程环境设计且只使用一个进程进行垃圾回收,会暂停所有的用户线程,所以不适合高并发,快速响应的服务器环境

    2.并行垃圾收集器

      多个垃圾线程并行工作,此时用户线程是暂停的,适用于科学计算/大数据处理平台等弱交互场景使用

    3.并发垃圾收集器

      用户线程和垃圾回收线程同时进行,可交互执行,不需要暂停用户线程,互联网公司使用的较多,可以满足对交互时间有需求的场景

    4.G1垃圾收集器

      将堆内存分割为不同的区域,然后并发的对其进行垃圾回收操作

  3.垃圾回收器的类型/垃圾回收算法(垃圾收器就是具体实现这些GC算法并实现内存回收,不同版本,不同厂商的虚拟机实现的差别很大)

    垃圾回收器

      1.UseSerialGC             

      2.UseParNewGC        

      3.UseParallelGC        

      4.UseConcMarkSweepGC        

      5.UseParallelOldGC

      6.UseG1GC

    垃圾收集算法

      1.SerialCopying (Young区)

      2.ParallelScavenge(Young区)

      3.ParNew(Young区)

      4.SerialMSC(Old区)

      5.ParallelCompacting(Old区)

      6.CMS(Old区)

      7.G1(Young&Old)

  年轻代(Young区)

    串行GC (Serial Copying)

      串行GC是最古老,稳定,高效的收集器,只使用一个线程去回收,但其在进行垃圾回收的过程中可能会产生较长的停顿(SWT)状态,虽然

    在收集垃圾的过程中需要暂停所有其他的工作线程,但是它简单高效,对于限定的单个CPU来说,没有线程交互的开销可以获得最高的单线程

    垃圾收集的效率,因此Serial垃圾收集器依然是Java虚拟机在Client模式下默认的新生代收集器

    配置:   -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialGC

     开启后会使用Serial + Serial Old的收集组合,表示新生代,老年代都会使用串行垃圾收集器,新生代使用复制算法,老年代使用标记整理算法

    

    并行GC(ParNew)

      使用多线程进行垃圾回收,在垃圾收集时会暂停其他所有的工作线程直到垃圾收集结束.ParNew实际上就是Serial收集器在新生代多线程

    版本,最常见的使用场景是配合老年代的CMS工作,其余的和Serial收集器完全一样.ParNew在垃圾收集过程中同样要暂停其他所有的工作线程

    ,它是很多Java虚拟机在Server的默认垃圾收集器

    配置:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParNewGC

    开启后会使用ParNew + CMS +Serial Old(备份)的组合,新生代使用复制算法,老年代使用标记整理算法,ParNew+Tenured这样的组合在Java8以后不再被推荐

    并行GC(Parallel)/(ParallelScavenge)

      ParallelScavenge类似于ParNew也是一个新生代垃圾收集器,也是一个基于多线程的垃圾收集器,它是串行收集器正在新生代和老年代的并行化,可以控制

    吞吐量,高吞吐量意味着高效的利用CPU的时间,多用于后台计算而不需要太多交互的任务.自适应调节策略也是ParallelScavenge收集器和ParNew收集器的一

    个很大的区别,JVM会根据当前系统运行的情况收集性能监控信息,动态调整这些参数以提供最适合的停顿时间或最大吞吐量(-XX:MaxGCPauseMillis)

    配置:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParallelGC

    开启后新生代使用复制算法,老年代使用标记整理算法

  老年代

    CMS收集器(并发标记清除)

      是以一种最短回收时间为目标的收集器,适用于大型的B/S系统的服务器上,重视服务器的响应速度,希望系统的停顿时间最短,适用于堆内存大,CPU核数较多                的服务端应用,也是G1出现之前大型应用首选的垃圾收集器.由于耗时最长的并发标记和并发清除的过程中,垃圾收集线程可以和用户线程一起工作,所以整体来看

    CMS收集器的内存回收和用户的工作线程是并发执行的.

    配置:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseConcMarkSweepGC

    开启后将自动打开-XX:+UseParNewGC,使用ParNew(Young区) + CMS(区) + Serial Old的收集器组合,Serial Old作为CMS出错的后备收集器

    收集步骤:

      1.初始标记      只是标记一下GC Root能直接关联的对象,速度很快,但任然需要暂停所有的工作线程

      2.并发标记   进行GC Roots跟踪过程,和用户的线程一起,不需要暂停工作线程,主要标记过程,标记全部对象

      3.重新标记   为了修改并发标记的时间,因用户进程继续运行而导致标记产生变动的那一部分对象的标记记录,任然需要暂停所有的工作线程,由于在

              并发标记时,用户线程依然运行.因此在正式清理前,再做修正

      4.并发清除   清除GC Roots不可达对象,和用户线程一起工作,不需要暂停工作线程,基于标记的结果,直接清理对象

    优缺点:

      优点:  并发收集低停顿

      缺点:       并发执行,对CPU压力大(由于并发进行,CMS在收集与应用线程会同时增加对堆内存的占用,也就是CMS必须要在老年代堆内存用尽之前完成垃圾

                     回收,否则CMS回收失败时,触发担保机制,串行老年代收集器将会以SWT的方式进行一次GC,从而造成较大的停顿)

           采用标记清除算法会造成大量的碎片(标记清除算法无法整理空间碎片,老年代空间会随着应用时长被逐步耗尽最后不得不通过担保机制对堆内

                     存进行压缩,CMS也提供了参数-XX:CMSFullGCsBeForeCompaction(默认为0,每次都进行内存整理)来指定多少次CMS

                     收集后,进行一次压缩的Full GC)

    Serial Old收集器

      Serial Old是Serial垃圾收集器的老年代版本,是个单线程的收集器,使用标记整理算法,这个收集器也是主要运行在Client的默认的Java虚拟机的老年代垃圾

    收集器,现在在JDK1.8之后,已经不推荐使用了.

    配置:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialOldGC

    垃圾收集器组合

    1.单CPU或小内存,单机程序 -XX:+UseSerialGC

    2.多CPU追求最大吞吐量,如计算后台的应用, -XX:+UseParallelGC / -XX:+UseParallelOldGC

    3.多CPU追求低停顿时间,需要快速响应,如互联网应用 -XX:+UseConcMarkSweepGC / -XX:+UseParNewGC

参数 新生代垃圾收集器 新生代算法 老年代垃圾收集器 老年代算法
-XX:UseSerialGC SerialGC 复制 SerialOldGC  标整
-XX:+UseParNewGC ParNew 复制 SerialOldGC  标整
-XX:+UseParallelGC Parallel[Scavenge] 复制 ParallelOldGC  标整
-XX:+UseParallelOldGC 同上 同上 同上  同上
-XX:+UseConcMarkSweepGC ParNew 复制

CMS+Serial Old收集器的组合

Serial Old作为CMS出错的后备

 标清
-XX:+UseG1GC 标清 标清 标清 标清

    G1垃圾收集器

      1.以往垃圾收集器的特点

        1.年轻代和老年代必须是各自独立且连续的内存块

        2.年轻代收集使用单eden+S0+S进行复制算法

        3.老年代收集必须扫描整个老年区

        4.都已尽可能少而快速地执行GC为设计原则

      2.G1收集器的特点

        G1是一种面向服务端的垃圾收集器,应用在多处理器和大内存容量的环境中,在实现高吞吐量的同时尽可能满足垃圾收集器暂停时间的特性,此外

        还具有如下需求:

            1.和CMS一样可以和应用程序并发执行

            2.整理空闲空间速度更快

            3.需要更多的时间来预测GC的停顿时间

            4.不希望牺牲大量的吞吐性能

            5.不需要更大的Java Heap

      3.为什么使用G1收集器

        1.G1能够充分利用多CPU,多核环境硬件优势,尽量缩短SWT

        2.G1整体上采用标记-整理算法,剧不是通过复制算法,不会产生内存碎片

        3.宏观上看G1之中不在区分年轻代和老年代.把内存划分成独立的子区域Region,可近似理解为围棋棋盘

        4.G1收集器将整个的内存区域都混在了一起,但其本身依然在小范围内要进行年轻代和老年代的区分,保留了新生代和老年代,但它们不再是物理隔离,

           而是一部分Region的集合不需要Region是连续的,也就是说依然会采用不同的GC方式来处理不同的区域

        5.G1虽然也是分代收集器,但整个内存区域不存在物理上的年轻代和老年代的区别,也不需要完全独立的survivor堆做复制准备.G1只有逻辑上的分代

           概念,或者说每个分区可能随G1的运行在不同代之间前后切换最大的好处是化整为零,避免了全内存的扫描,只需要按照区域进行扫描即可

      4.G1的算法原理

        1.G1将堆划分为若干个区域,仍然属于分代收集器,这些Region一部分包含新生代,新生代的垃圾收集依然采用暂停所有线程的方式将存活的对象拷贝到

       老年代或者Survivor区.

        2.这些Region中一部分包含老年代,G1收集器通过将对象从一个区域复制到另一个区域完成清理工作,这也意味着,在正常的清理过程中,G1完成了堆的

       压缩,这样就不再会有CMS内存碎片的问题了

        3.在G1中还有一种特殊的区域,称为Humongous区,如果一个对象的空间超过了分区容量的50%,G1收集器就认为这是一个巨型的对象,这些巨型对象会

       直接的分配在老年代,但如果是一个短期存在的巨型对象,就会对垃圾收集器造成负面的影响,为了解决这类问题,G1专门划分了一块Humongous区域专门

       用来存放巨型对象,如果H区放不下一个巨型对象,G1就会寻找连续的H区来存储,为了能够找到联系的H区,有时不得不启用Full GC

    5.回收过程

         1.Eden区数据转移到Survivor区,假如Survivor区的内存不够,Eden区会晋升到Old区

         2.Survivor区域的数据会移动到新的Survivor区,部分数据会晋升到Old区

         3.最后Eden区回收完毕,GC结束,用户的进程继续执行

    6.G1常用的配置参数

         1.-XX:+UseG1GC  使用G1垃圾收集器

         2.-XX:G1HeapRegionSize = n 设置G1区域的大小,值为2的指数幂,范围是1~32MB,目标是根据Java堆的大小划分出2048个区域

         3.-XX:MaxGCPauseMillis = n   最大GC的停顿时间,这是个软目标,JVM尽可能停顿小于这个时间

         4.-XX:InitiatingHeapOccupancyPercent = n 堆占用多少就触发GC,一般是45%

         5.-XX:ConcGCThread = n  并发GC使用的线程数

         6.-XX:G1ReservePercent = n  设置做为空闲空间的预留内存百分比,以降低目标发生内存溢出的风险,默认值是10%,一般不改

        7.和CMS相比有哪些优势

         1.G1不会产生内存碎片

       2.可以精确的控制停顿,该收集器把整个堆划分成固定大小的区域,每次会根据允许停顿的时间去收集垃圾最多的区域

    G1收集器的目标是取代CMS收集器,它同CMS相比,在以下方面更具有优势,主要应用在多CPU和大内存服务器环境下,极大的减少垃圾收集的停顿时间,全面提升

    服务器的性能,逐步替代CMS收集器.主要改变的是Eden,Survivor和Tenured等区域不再是连续的了,而是变成一个个大小一样的Region,每个Region从1M到32M

    不等.一个Region可能属于Eden,Survivor,Tenured任意的内存区域.这样即不会产生内存碎片,同时垃圾收集时间上添加了预测机制,用户可以指定希望的停顿时间.

    8.配置

       1.生产系统配置               -XX:+UseG1GC -Xms32G -XX:MaxGCPauseMillis=100

       2.Spring boot微服务        java -server -Xms1024 -Xmx1024m -XX:+UseG1GC -jar 需要的微服务名称

 

JVM中的GC算法,JVM参数,垃圾收集器分类的更多相关文章

  1. JVM的分区+查看GC对象是否存活+3种GC算法+7种垃圾收集器+如何减少GC次数

    一.JVM的分区:   1.程序计数器(私有) 程序计数器是一块较小的内存分区,你可以把它看做当前线程所执行的字节码的指示器. 在虚拟机的概念模型里,字节码解释器工作时,就是通过改变计数器的值来选择下 ...

  2. JVM中内存回收深入分析,各种垃圾收集器

    JVM启动有两种模式,client和server 一般JVM启动时会根据主机情况分析选择采用那种模式启动 可发现是server模式 JVM中尤其需要关注的就是HEAP堆区 堆区分为新生代和老年代 新生 ...

  3. 这货到底还是不是垃圾?【垃圾回收GC算法JVM篇四】

    目录 1.判断对象是否存活的JVM两种计数算法 2.垃圾收集算法 3.垃圾回收算法小结 垃圾收集 Garbage Collection 通常被称为"GC", 在jvm 中,程序计数 ...

  4. JVM学习笔记——GC算法

    GC 算法 GC 即 Garbage Collection 垃圾回收.JVM 中的 GC 99%发生在堆中,而 Java 堆中采用的垃圾回收机制为分代收集算法.即将堆分为新生代和老年代,根据不同的区域 ...

  5. JVM(三) 垃圾回收时间点和垃圾收集器

      收集器组合章节来自第一篇参考文章,非原创,作者总结地非常好!          分代收集相关概念来自参考文章第二篇,非原创         第二篇参考资料的文章质量很高,推荐阅读! 分代收集(Ge ...

  6. GC之一--GC 的算法分析、垃圾收集器、内存分配策略介绍

    一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...

  7. Java虚拟机9:垃圾收集(GC)-4(垃圾收集器)

    1.前言 垃圾收集器是前一章垃圾收集算法理论知识的具体实现了,不同虚拟机所提供的垃圾收集器可能会有很大差别,另外我们必须提前说明一个道理:没有最好的垃圾收集器,更加没有万能的收集器,只能选择对具体应用 ...

  8. jvm系列(三):GC算法 垃圾收集器

    原文出处:纯洁的微笑 这篇文件将给大家介绍GC都有哪几种算法,以及JVM都有那些垃圾回收器,它们的工作原理. 概述 垃圾收集 Garbage Collection 通常被称为"GC" ...

  9. 深入理解JAVA虚拟机(内存模型+GC算法+JVM调优)

    目录 1.Java虚拟机内存模型 1.1 程序计数器 1.2 Java虚拟机栈 局部变量 1.3 本地方法栈 1.4 Java堆 1.5 方法区(永久区.元空间) 附图 2.JVM内存分配参数 2.1 ...

随机推荐

  1. P1098 方程解的个数

    题目描述 给出一个正整数N,请你求出x+y+z=N这个方程的正整数解的组数(1<=x<=y<=z<1000).其中,1<=x<=y<=z<=N . 输入 ...

  2. linux 分配和释放设备编号

    在建立一个字符驱动时你的驱动需要做的第一件事是获取一个或多个设备编号来使用. 为 此目的的必要的函数是 register_chrdev_region, 在 <linux/fs.h>中声明: ...

  3. Redis 命令行工具能这样用你知道了吗?

    我们天天都在使用 Redis 内置的命令行工具 redis-cli,久而久之以为它就是一个简单的交互式 Redis 数据结构手工操作程序,但是它背后强大的功能绝大多数同学可能闻所未闻.本节我们一起来挖 ...

  4. Spring Security 5中 PasswordEncoder的使用

    在最新的 Spring Security 5发布版本中, 出于安全性的考虑调整了PasswordEncoder的实现与使用策略. 1.以前常用的实现 StandardPasswordEncoder, ...

  5. java 内省综合案例和Beanutils工具包

    演示用eclipse自动生成 ReflectPoint类的setter和getter方法. 直接new一个PropertyDescriptor对象的方式来让大家了解JavaBean API的价值,先用 ...

  6. POJ 1236 Network of Schools(tarjan)

    Network of Schools Description A number of schools are connected to a computer network. Agreements h ...

  7. P1014 高精度减法

    题目描述 给你两个很大的正整数A和B,你需要计算他们的差. 输入格式 输入一行包含两个正整数A和B,以一个空格分隔(A和B的位数都不超过 \(10^5\) ,但是B有可能比A大) 输出格式 输出一行包 ...

  8. ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(9)之系统登录

    前面我们已经做好了一个文章管理功能模块,接下来,我们回头来做登录窗口,登录不仅涉及到登录验证还涉及到登录日志还有缓存时长等. 对于缓存的相关设置,我们已经写好封装在Bobo.Utilities.dll ...

  9. linux 一个使用整页的 scull: scullp

    为了真实地测试页分配, 我们已随其他例子代码发布了 scullp 模块. 它是一个简化的 scull, 就像前面介绍过的 scullc. scullp 分配的内存量子是整页或者页集合: scullp_ ...

  10. Linux 内核SBus连接

    当大部分计算机配备有 PCI 或 ISA 接口总线, 大部分老式的基于 SPARC 的工作站使用 SBus 来连接它们的外设. SBus 使一个非常先进的设计, 尽管它已出现很长时间. 它意图是处理器 ...