jvm课程总结以及回顾

JVM性能调优:共10节课

 

 

20.7.16-虚拟机的前世今生和JVM内存区域

时间轴:完成

 

收获:

   大致理解jvm内存结构:方法区,堆和栈

     方法区:主要存放class,静态变量,changl

     堆:放运行时候的对象,GC主要是回收这块区域的内存

     栈:线程私有,先进后出

           私有部分: 虚拟机栈,本地方法栈,程序计数器

           公用部分:方法区和堆

     直接内存(堆外内存): ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10240);

 

 

20.7.19-深入理解JVM的内存区域

时间轴:完成

收获:

     1.程序计数器也是 JVM 中唯一不会 OOM(OutOfMemory)的内存区域

     2.栈溢出,容易发生此类现在的原因,是由于方法之间的递归调用。(java.lang,StackOverflowError)

     3.堆溢出:不停的new 对象,并且在new的过程中,GC会进行回收,发现无法回收时,抛出异常OOM(Out Of Memory)

     4.方法区溢出:

            4.1) 运行时,常量池溢出

            4.2) 方法区中,保存的CLass对象没有及时回收或者Class信息占用的内存超过了我们的配置。(此发生的概率很低)

         拓展:cglib可以在运行期拓展Java类与实现java接口。

    5.本机直接内存(堆外内存)溢出:

           直接内存,一般不受限于虚拟机,只能通过配置限制堆外内存的使用。如果产生的对象大于配置或者超出实体机器的内存,才会抛出此错误。一般只能通过Dump进行排查。

 

 

20.7.21-玩转JVM中的对象及引用

 

时间轴:已完成

收货:

内存分配:

      1.指针碰撞:应对规整的内存进行,将指针往后移动(jvm sport 采用的方式)

      2.空闲列表: 不规整的内存分配,需要维护一张“空闲列表”

分配内存保证的并发安全

     1.CAS分配(Compare And Swap),比较再交换,CPU自己实现的

     2.分配缓存TLAB(Thread Local Allocation Buffer),每个线程启动的时候,从Eden区域申请一块私有内存单独给线程使用,不够了再申请一块

 

 

 

判断对象的存活:

   1.引用计数法:每当一个地方引用他,计数器加1.(劣势:互相引用,及时是垃圾,也无法清除)

   2.可达性分析:

       根可达:

             1.虚拟机栈(栈帧中的本地变量表)中引用的对象;各个现场被调用方法堆栈中使用到的参数、局部变量、临时变量等。

             2.方法区中类静态属性引用的对象;java 类的引用类型静态变量。

             3.方法区中常量引用的对象;比如:字符串常量池里的引用。

             4.本地方法栈中 JNI(即一般说的 Native)引用的对象

             5.JVM 的内部引用(class 对象、异常对象 NullPointException、OutofMemoryError,系统类加载器)。(非重点)

             6.所有被同步锁(synchronized 关键)持有的对象。(非重点)

             7.JVM 内部的 JMXBean、JVMTI 中注册的回调、本地代码缓存等(非重点)

             8.JVM 实现中的“临时性”对象,跨代引用的对象(在使用分代模型回收只回收部分代的对象,这个后续会细讲,先大致了解概念)(非重点)

 

各种引用:

         强引用(被引用的对象,及时OOM都不会回收)

         软引用(系统OOM之前,回收)

         弱引用(下一次垃圾回收会被清理)

         虚引用(随时被回收)

 

对象的分配策略:

 

   1. 在堆空间中,对象优先再Eden区分配,经过minorGC,再from和to区进行年龄的增长,15次后还存活的对象,进行老年代。

   2.大对象直接进入老年代

   3.长期存活的对象,直接进入老年代

   4.对象年龄动态判定:如果在 Survivor 空间中 相同年龄所有对象大小的总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到 MaxTenuringThreshold 中要求的 年龄。

 

拓展:

  逃逸分析说的是,栈上可以分配内存,每个线程启动的时候,默认分配了1M的栈内存,当这个方法的局部变量,仅仅在此方法内用到了,那么这个变量,就没有逃逸出去,就会再栈上分配内存,以免再堆中分配内存,造成频繁的垃圾回收。

 

 

20.7.23- 分代回收机制及垃圾回收算法

 

时间轴:完成

收获:

1、 新生代回收(Minor GC/Young GC):指只是进行新生代的回收。

2、 老年代回收(Major GC/Old GC):指只是进行老年代的回收。目前只有 CMS 垃圾回收器会有这个单独的回收老年代的行为。 (Major GC 定义是比较混乱,有说指是老年代,有的说是做整个堆的收集,这个需要你根据别人的场景来定,没有固定的说法)

3、 整堆回收(Full GC):收集整个 Java 堆和方法区(注意包含方法区)

 

 

垃圾回收算法:

    1、复制算法(Copying):速度快,内存利用率仅仅只有50%

    2.、Appel式回收(新生代模型):理论依据->新生代中的对象 98%是“朝生夕死”的    (java新生代采用)

    3、标记-清除算法(Mark-Sweep):清理速度比较快,容易产生大量不连续的内存碎片

    4、标记-整理算法(Mark-Compact):标记整理算法虽然没有内存碎片,但是效率偏低。(java老年代,full GC采用)

注:垃圾回收均会产生Stop The World (STW)

 

CMS垃圾回收器:

 

初始标记—> 并发标记 —>重新标记 —>并发清楚

 

 

Garbage First(G1)垃圾回收器:

设计思想

随着 JVM 中内存的增大,STW 的时间成为 JVM 急迫解决的问题,但是如果按照传统的分代模型,总跳不出 STW 时间不可预测这点。 为了实现 STW 的时间可预测,首先要有一个思想上的改变。G1 将堆内存“化整为零”,将堆内存划分成多个大小相等独立区域(Region),每一个 Region 都可以根据需要,扮演新生代的 Eden 空间、Survivor 空间,或者老年代空间。回收器能够对扮演不同角色的 Region 采用不同的策略去处理,这样无论是 新创建的对象还是已经存活了一段时间、熬过多次收集的旧对象都能获取很好的收集效果。

Region

Region 可能是 Eden,也有可能是 Survivor,也有可能是 Old,另外 Region 中还有一类特殊的 Humongous 区域,专门用来存储大对象。 G1 认为只要大小超过 了一个 Region 容量一半的对象即可判定为大对象。每个 Region 的大小可以通过参数-XX:G1HeapRegionSize 设定,取值范围为 1MB~32MB,且应为 2 的 N 次 幂。而对于那些超过了整个 Region 容量的超级大对象,将会被存放在 N 个连续的 Humongous Region 之中,G1 的进行回收大多数情况下都把 Humongous Region 作为老年代的一部分来进行看待。

 

初始标记:

仅仅标记GC Roots能直接关联到的对象

 

并发标记:

从 GC Root 开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫 描 完 成 以 后 , 并 发 时 有 引 用 变 动 的 对 象 , 这 些 对 象 会 漏 标 ( 后 续 再 讲 三 色 标 记 的 时 候 会 细 讲 这 个 问 题 ) , 漏 标 的 对 象 会 被 一 个 叫 做 SATB(snapshot-at-the-beginning)算法来解决(这个下节课会细讲)

 

最终标记( Final Marking)

对用户线程做另一个短暂的暂停,用于处理并发阶段结后仍遗留下来的最后那少量的 SATB 记录(漏标对象)。

 

筛选回收( Live Data Counting and Evacuation)

负责更新 Region 的统计数据,对各个 Region 的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个 Region 构 成回收集,然后把决定回收的那一部分 Region 的存活对象复制到空的 Region 中,再清理掉整个旧 Region 的全部空间。这里的操作涉及存活对象的移动, 是必须暂停用户线程,由多条收集器线程并行完成的。

 

 

小知识:

TAMSTop at Mark Start 是什么?

要达到 GC 与用户线程并发运行,必须要解决回收过程中新对象的分配,所以 G1 为每一个 Region 区域设计了两个名为 TAMS(Top at Mark Start)的指针, 从 Region 区域划出一部分空间用于记录并发回收过程中的新对象。这样的对象认为它们是存活的,不纳入垃圾回收范围。

 

 

20.7.26 JVM面试“核武器”JVM底层细节

 

时间轴:完成

收获:

三色标记:

CMS 中的解决方案

Incremental Update 算法 当一个白色对象被一个黑色对象引用,将黑色对象重新标记为灰色,让垃圾回收器重新扫描

 

G1 中的解决方案

SATB(snapshot-at-the-beginning) 刚开始做一个快照,当 B 和 C 消失的时候要把这个引用推到 GC 的堆栈,保证 C 还能被 GC 扫描到,最重要的是要把这个引用推到 GC 的堆栈,是灰色对 象指向白色的引用,如果一旦某一个引用消失掉了,我会把它放到栈(GC 方法运行时数据也是来自栈中),我其实还是能找到它的,我下回直接扫描他 就行了,那样白色就不会漏标。 对应 G1 的垃圾回收过程中的: 最终标记( Final Marking) 对用户线程做另一个短暂的暂停,用于处理并发阶段结后仍遗留下来的最后那少量的 SATB 记录(漏标对象)。

 

 

 

 

 

20.7.28  Class文件结构及深入字节码指令

 

时间轴:完成

收获: 学会了用 javap -v *.java 看字节码

idea 用jclasslib工具查看

jd-gui 查看反编译

 

字节码有兴趣可以记忆,我兴趣不是很大

 

 

2020.7.30玩转类加载与类加载器

时间轴:模糊完成

收获:

 

 

 

 

2020.8.2 方法调用底层实现

时间轴:

收获:

 

 

 

2020.8.4 java语法糖及实现

时间轴:

收获:

 

 

2020.8.6 GC调优知识只工具篇(原生+Arthas)

时间轴:

收获:

 

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值