JVM调优--GC基础

该视频是即将要参加的公开课视频的前置内容

主要内容:Garbage Collector 和GC tuning

主讲人是: 马士兵

目标: 在正式上课之前的基础课程. 


 整体上来讲, 看了马士兵的预习视频以后, 感觉对GC又复习了一遍. 此次预习, 主要目的是7号晚上会有一个JVM调优的课程, 全称也有几点感悟

1. 理论偏多, 也就是更多的是概念性的问题.

2. 记得两年前撸过一遍jvm内存模型, jvm GC, 当时学得很认真, 所以, 这次听老师在讲GC, 在理解上更近了一步. 可喜的是,当时的笔记记在哪里了?已经找不到了, 那是系统的学习,讲解的更详细.

3. 也是我思考的问题. 学习了这些东西, 要如何能够应用在实际工作中. 学是第一步, 更重要的是用.

4. 期待今晚上的课程, 据说很有用

 

回到正题, 整理今天的笔记

以下是课程开始前, 马老师给出的一个jvm的架构图, 让我垂涎欲滴的. 要是能够全部掌握, 应该在代码上会大进一步.


本节讲解的主要内容如下:

GC的基础知识

1. 什么是垃圾

  a. 在c c++ java中是如何申请内存, 又是如何回收的呢?

    c语言申请内存: malloc  / free

    c++ : new / delete

    java : new / 无

    java采用的是自动回收机制

  b. 手动回收和自动回收

    自动回收: 编程简单, 系统部容易出错, 但相对效率较低

    手动回收: 变成复杂, 容易出现以下两类问题, 但效率高

    - 忘记回收

    - 多次回收

  c. 那么什么是GC呢? 没有任何引用指向的一个对象或者一堆对象. 解释一下

       

 

   栈空间里有一个对象, 这个对象new出来了一个成员变量, 这个变量指向了另外一个对象. 当我们把这个成员变量设置为null, 关系变为如下:

 

   这时, 这个对象就变成垃圾. 这是单个对象变为垃圾的情况. 

  还有一种. 如下:

 

   这种是,好多个对象互相之间有引用, 但是,没有任何引用指向它, 那么, 他也是垃圾. 是一堆垃圾.

 

2. 如何定位垃圾

  两种方法:

  1. Reference Count: 引用计数

 

   在一个对象上标记数字, 有几个对象引用他了. 比如现在有3个, 这标记为3. 知道对象标记为0, 则认为他是一个垃圾

   引用计数存在的问题: 当一堆对象, 彼此相互引用, 他们的计数始终都不为0, 但是他们没有被其他对象引用, 是一对垃圾, 通过引用计数没法判断, 所以, 又有下面这种计数方式--根可达算法

 

  2. Root Searching根可达算法: 

  

   通过程序找到根对象, 通过跟对象找到关联的对象, 这些都不是垃圾, 其他的都是垃圾. 

  根对象指的是什么呢?

  程序运行, 会有一个main方法, 这个肯定不是垃圾. 

  线程栈里的局部变量, 静态变量, 常量池, JNI指针引用到的变量.

  jvm 文档给出的那些对象是根对象呢? JVM stack(栈对象), native method(本地方法栈), run-time constant(常量池), static references in method area(静态方法区), Clazz(内存中的class)

3. 常见的垃圾回收算法

  a. Mark Sweep标记清除:

  

 

 

  标记黑色可回收的对象然后清楚. 优点是速度快, 缺点, 从清除后的图像可以看出, 内存被分成了一小块一小块, 有碎片

  b. copy拷贝:

  

 

 

  将内存一分为二: 然后将第一部分的存活对象全部拷贝到第二部分. 在对第一部分整体清除.

  拷贝的速度是很快的, 缺点是耗费内存. 本来5G空间就足够了, 但是用标记清楚, 就要配备10G的内存. 

  c. Mark Compact标记压缩:

  

 

 

   将可回收对象标记出来,然后把后面的存活对象拷贝到可回收的位置, 在做标记和清除的过程中, 做了压缩和整理.

  好处是有用的对象放一块, 可以有整块的空间, 资源也得到了充分的利用. 缺点是:效率偏低.

4. JVM分代内存模型

  a. 部分垃圾回收期使用的模型:

  b. 新生代New + 老年代Old + 永久代(1.7) / 元数据区(1.8) Metaspace

    1) 永久代和元数据都是装class

    2)永久代必须指定大小限制, 元数据可以限制, 也可以不限制,无上限(受限于物理内存)

    3) 字符串常量 1.7-永久代, 1.8-元数据

  c. 新生代 = Eden + 2个survivor . 对新生代对象的回收叫YGC.

    1) YGC回收后,大多数会被回收. 活着的对象进入s1

    2) 再次YGC, 将Eden+s1对象copy到s2, 然后清空.

    3) 再次YGC, Eden + s2 对象 copy到s1, 以此循环

    4) 年龄达到一定阶段, 直接放入老年代.

    5) 如果大对象s2放不下,直接进入老年代.

  d. 老年代: 

    1) 装的顽固分子

    2) 垃圾回收叫FGC

 

  e. GC tuning(Generation) GC调优, 调什么呢?

    1) 尽量减少FGC

    概念: MinorGC 就是 YGC

        MajorGC 就是 FGC

 

      STW

  堆内存逻辑分析:

  

 

 

 

5. 垃圾回收器

  垃圾回收算法有哪些?

  

 

 

   红线圈出的是分代模型, 上面是新生代使用的模型, 下面是老年代使用的模型, 右侧跨在中间的不在区分新生代和老年代.

  线上运行的系统, 多数是红线圈出的部分. 所以我们调优也是针对这部分. 仔细看, 新生代和老年代中间有虚线, 虚线代表组合.

  a. Serial : 串行回收

  

 

 

   hotspot是这么定义的: 停止整个世界, 进行单线程GC处理

  意思是: 蓝线代表有多个线程正在执行, 然后, 要进行gc回收. 所有线程都要停止, gc回收线程是单线程. gc回收完, 继续执行主任务, 依次循环.

  Serial 使用在新生代

  Serial Old 使用在老年代

  b. Parallel Scavenge: 并行回收

  Parallel Scavenge: 用在新生代

  Parallel Old: 用在老年代

  

 

 

  和Serial并行回收对比, 垃圾回收采用的是多线程并行回收. 效率比单线程高

  3. ParNew:配合CMS的并行回收, 应用在年轻代

  

 

 

   他也是并行回收, 那么他和Parallel Scavenge的区别是什么呢? 看hotspot给出的, 重点在于ParNew可以和CMS配合使用.

   d. ConcurrentMarkSweep: 简称CMS. 

    1) 应用在老年代

    2) 在垃圾回收的过程中, 应用程序也能运行. 所以叫做并行

    3)这个回收机制也存在各种问题, 达存在的意义是一个承上启下的过度, 由此产生了下面几种回收机制.

  

 

 

     详细在下节课解释

     5. G1:(10ms)

     6. ZGC: (1ms): 可以pkc++

     7. Shenandoah:

    8. Eplison

  目前,我们调优主要调的是哪一块呢? Serial和Serial Old, Parallel Scavenge和Parallel Old.

  原因是: 1.8默认的垃圾回收器是PS + Parallel Old. 我们使用的时候很少去手动设置

6. jvm调优第一步, 了解生产环境下的垃圾回收组合

  a. JVM命令行参数的参考

  b. JVM命令参数分类

    1) 标准参数: -开头, 所有的HotSpot都支持

      例如: java -version

    2)非标准参数: -X开头, 特定版本的HotSpot支持

      在命令行输出 java -X 可以查看到非标参数

    3)不稳定参数: -XX开头, 下个版本可能取消

      在命令行输出 java -XX:+PrintFlagsFinal

      java -XX:+PrintCommandLineFlags, 这个命令用来查看, 再生产环境中jvm使用了哪些参数. 不会影响线上程序的运行.

      

 

       这是我的java程序启动的时候的参数

      1. InitialHeapSize :初始堆大小

      2. -XX: MaxHeapSize : 对最大大小

      3. -XX:+PrintCommandLIneFlags : 我当前执行的命令

      4. -XX:+UseCompressedClassPointers : 压缩指针

      5. -XX:UseCompressedOops : 压缩对象

      6. -XX: +UseParallelGC : 使用的GC是ParallelGC. 使用的就是(Parallel Scavenge + Parallel Old) .

    通过这个命令, 我们就知道我们使用的是什么样的GC类型了. 我的java 是1.8

 


本次预习就结束了, 看了一遍, 有整理了一遍笔记, 期待晚上的分享. 

 

posted @ 2020-02-07 04:04  盛开的太阳  阅读(482)  评论(0编辑  收藏  举报