JVM从入门到精通

查看JVM常用命令

  1. 查看GC信息
jstat -gcutil  1000

JVM从入门到精通_第1张图片

 jstat -gc  1000

在这里插入图片描述

  1. java和jvm的配置信息
jinfo  

JVM从入门到精通_第2张图片
在这里插入图片描述

cpu使用率

top -p 

JVM从入门到精通_第3张图片

课程结构
JVM从入门到精通_第4张图片

尚硅谷_宋红康_JVM从入门到精通: https://www.bilibili.com/video/BV1PJ411n7xZ?from=search&seid=12508719405042682431

参考笔记连接:
https://blog.csdn.net/weixin_45759791/category_10123040.html

jvm(java虚拟机):一次编译到处运行,自动的管理内存,自动垃圾回收,降低内存泄漏的概率

建议书籍:

JVM从入门到精通_第5张图片

一. JVM内存与垃圾回收篇概述

P2 02-如何看待Java上层技术与JVM
P3 03-为什么要学习JVM
P4 04-面向人群和课程特点

P5 05-官方规范下载与参考书目

JVM从入门到精通_第6张图片

P6 06-跨平台的语言Java和跨语言的平台JVM(java虚拟机)

java 因为有jvm 成了跨平台的语言
jvm(java虚拟机): 一个抽象的计算机
JVM从入门到精通_第7张图片

除了java以外可以使用jvm(java虚拟机)
jvm : 跨语言的平台
JVM从入门到精通_第8张图片

JVM从入门到精通_第9张图片

P7 07-字节码与多语言混合编程

  • 字节码:
    JVM从入门到精通_第10张图片
  • 多语言混合编程:
    JVM从入门到精通_第11张图片

P8 08-Java及JVM历史上的重大事件

JVM从入门到精通_第12张图片

P9 09-虚拟机与Java虚拟机介绍

JVM从入门到精通_第13张图片
JVM从入门到精通_第14张图片
JVM从入门到精通_第15张图片

P10 10-JVM的位置

  • JVM的位置:
    JVM从入门到精通_第16张图片

P11 11-JVM的整体结构

  • JVM的整体结构
    JVM从入门到精通_第17张图片
    更详细的图
    JVM从入门到精通_第18张图片

P12 12-Java代码执行流程

  • Java代码执行流程
    JVM从入门到精通_第19张图片

P13 13-区分栈的指令集架构和寄存器的指令集架构

JVM从入门到精通_第20张图片

P14 14-JVM的生命周期

  • JVM的生命周期![JVM从入门到精通_第21张图片
    JVM从入门到精通_第22张图片

P15 15-SUN Classic VM的介绍
P16 16-Exact VM的介绍

P17 17-HotSpot VM的介绍

JVM从入门到精通_第23张图片

P18 18-JRockit VM的介绍
P19 19-IBM J9 VM的介绍
P20 20-KVM、CDC、CLDC的介绍
P21 21-Azul VM和BEA Liquid VM的介绍
P22 22-Apache Harmony的介绍
P23 23-Microsoft JVM和TaobaoJVM
P24 24-Dalvik VM及其他虚拟机的介绍
P25 25-Graal VM的介绍

P26 26-内存结构概述

JVM从入门到精通_第24张图片

JVM从入门到精通_第25张图片
JVM从入门到精通_第26张图片

类加载子系统

P27 27-概述类的加载器及类加载过程

JVM从入门到精通_第27张图片
JVM从入门到精通_第28张图片
JVM从入门到精通_第29张图片

P28 28-类的加载过程一:Loading

JVM从入门到精通_第30张图片
JVM从入门到精通_第31张图片

JVM从入门到精通_第32张图片

JVM从入门到精通_第33张图片

P29 29-类的加载过程二:Linking


JVM从入门到精通_第34张图片

P30 30-类的加载过程三:Initialization
JVM从入门到精通_第35张图片
JVM从入门到精通_第36张图片
JVM从入门到精通_第37张图片
JVM从入门到精通_第38张图片

P31 31-几种类加载器的使用体会

JVM从入门到精通_第39张图片

JVM从入门到精通_第40张图片

JVM从入门到精通_第41张图片
JVM从入门到精通_第42张图片

P32 32-引导类、扩展类、系统类加载器的使用及演示

在这里插入图片描述
JVM从入门到精通_第43张图片

JVM从入门到精通_第44张图片
JVM从入门到精通_第45张图片

P33 33-为什么需要用户自定义类加载器及具体实现

JVM从入门到精通_第46张图片
P34 34-ClassLoader的常用方法及获取方法
P35 35-双亲委派机制的工作原理及演示
P36 36-双亲委派机制的优势
P37 37-沙箱安全机制
P38 38-类的主动使用与被动使用等

运行时数据区

运行时数据区常见面试题
百度
三面:说一下JVM内存模型吧,有哪些区?分别干什么的?

蚂蚁金服:
Java8的内存分代改进
JVM内存分哪几个区,每个区的作用是什么?
一面:JVM内存分布/内存结构?栈和堆的区别?堆的结构?为什么两个survivor区?
二面:Eden和survior的比例分配

小米:
jvm内存分区,为什么要有新生代和老年代

字节跳动:
二面:Java的内存分区
二面:讲讲vm运行时数据库区
什么时候对象会进入老年代?

京东:
JVM的内存结构,Eden和Survivor比例。
JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和survivor。

天猫:
一面:Jvm内存模型以及分区,需要详细到每个区放什么。
一面:JVM的内存模型,Java8做了什么改

拼多多:
JVM内存分哪几个区,每个区的作用是什么?

美团:
java内存分配
jvm的永久代中会发生垃圾回收吗?
一面:jvm内存分区,为什么要有新生代和老年代?

视频链接:https://www.bilibili.com/video/BV1PJ411n7xZ
三面:说一下JVM内存模型吧,有哪些区?分别干什么的?

蚂蚁金服:
Java8的内存分代改进
JVM内存分哪几个区,每个区的作用是什么?
一面:JVM内存分布/内存结构?栈和堆的区别?堆的结构?为什么两个survivor区?
二面:Eden和survior的比例分配

小米:
jvm内存分区,为什么要有新生代和老年代

字节跳动:
二面:Java的内存分区
二面:讲讲vm运行时数据库区
什么时候对象会进入老年代?

京东:
JVM的内存结构,Eden和Survivor比例。
JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和survivor。

天猫:
一面:Jvm内存模型以及分区,需要详细到每个区放什么。
一面:JVM的内存模型,Java8做了什么改

拼多多:
JVM内存分哪几个区,每个区的作用是什么?

美团:
java内存分配
jvm的永久代中会发生垃圾回收吗?
一面:jvm内存分区,为什么要有新生代和老年代?

JVM从入门到精通_第47张图片

P39 39-运行时数据区内部结构

JVM从入门到精通_第48张图片

  • 运行时数据区内部结构:

jdk1.8后方法区叫元数据区(元空间)

JVM从入门到精通_第49张图片
JVM从入门到精通_第50张图片

P40 40-JVM中的线程说明

JVM从入门到精通_第51张图片
JVM从入门到精通_第52张图片

P41 41-PC寄存器概述

  • PC寄存器的作用:

PC寄存器用于存储下一条要执行代码的地址,及PC寄存器指向下一条要执行的代码

pc寄存器没有GC(垃圾回收),也不会出现内存溢出

JVM从入门到精通_第53张图片
JVM从入门到精通_第54张图片
JVM从入门到精通_第55张图片
JVM从入门到精通_第56张图片

P42 42-PC寄存器的使用举例

P43 43-解决PC寄存器两个面试问题

JVM从入门到精通_第57张图片

JVM从入门到精通_第58张图片

第五章、虚拟机栈—栈 (重要)

P44 44-java虚拟机栈

栈不存在GC(垃圾回收)

JVM从入门到精通_第59张图片
JVM从入门到精通_第60张图片
JVM从入门到精通_第61张图片
JVM从入门到精通_第62张图片

P45 45-虚拟机栈的常见异常与如何设置栈大小

JVM从入门到精通_第63张图片
递归自己调自己的方法,在递归没有结束时一直不释放栈内存,如果递归很深,容易出现栈溢出/内存泄漏
JVM从入门到精通_第64张图片
JVM从入门到精通_第65张图片
JVM从入门到精通_第66张图片
JVM从入门到精通_第67张图片

P46 46-栈的存储结构和运行原理

JVM从入门到精通_第68张图片
JVM从入门到精通_第69张图片

JVM从入门到精通_第70张图片
JVM从入门到精通_第71张图片

P47 47-栈桢的内部结构

JVM从入门到精通_第72张图片

P48 48-局部变量表结构的认识

JVM从入门到精通_第73张图片
JVM从入门到精通_第74张图片

P49 49-字节码中方法内部结构的剖析
P50 50-变量槽slot的理解与演示
P51 51-静态变量与局部变量的对比及小结
P52 52-操作数栈的特点
P53 53-涉及操作数栈的字节码指令执行分析
P54 54-栈顶缓存技术

P55 55-动态链接的理解与常量池的作用

JVM从入门到精通_第75张图片

为什么需要运行时常量池?

因为在不同的方法,都可能调用常量或者方法,所以只需要存储一份即可,节省了空间

常量池的作用:就是为了提供一些符号和常量,便于指令的识别

P56 56-方法的绑定机制:静态绑定与动态绑定

P57 57-4种方法调用指令区分非虚方法与虚方法

在这里插入图片描述

JVM从入门到精通_第76张图片

P58 58-invokedynamic指令的使用

P59 59-方法重写的本质与虚方法表的使用

JVM从入门到精通_第77张图片
JVM从入门到精通_第78张图片
如下图所示:如果类中重写了方法,那么调用的时候,就会直接在虚方法表中查找,否则将会直接连接到Object的方法中。
JVM从入门到精通_第79张图片

P60 60-方法返回地址的说明
P61 61-栈桢中的一些附加信息

P62 62-虚拟机栈的5道面试题

JVM从入门到精通_第80张图片

栈的相关面试题

  1. 举例栈溢出的情况?(StackOverflowError)
    通过 -Xss设置栈的大小, 递归深度很深,或者递归出现死循环

  2. 调整栈大小,就能保证不出现溢出么?
    不能保证不溢出, 递归深度很深,或者递归出现死循环

  3. 分配的栈内存越大越好么?
    不是,一定时间内降低了OOM(内存溢出)概率,但是会挤占其它的线程空间,因为整个空间是有限的。

  4. 垃圾回收是否涉及到虚拟机栈?
    不会

  5. 运行时数据区,是否存在Error和GC?

JVM从入门到精通_第81张图片

  1. 方法中定义的局部变量是否线程安全?
    具体问题具体分析
    何为线程安全?
  • 如果只有一个线程才可以操作此数据,则必是线程安全的
  • 如果有多个线程操作,则此数据是共享数据(由外部传入的参数,或内部参数返回,参数的作用域不止在方法内部),如果不考虑共享机制,则为线程不安全
    总结一句话就是:如果对象是在内部产生,并在内部消亡,没有返回到外部,那么它就是线程安全的,反之则是线程不安全的。
/**
 * 面试题
 * 方法中定义局部变量是否线程安全?具体情况具体分析
 * 何为线程安全?
 *    如果只有一个线程才可以操作此数据,则必是线程安全的
 *    如果有多个线程操作,则此数据是共享数据,如果不考虑共享机制,则为线程不安全
 * @author: 陌溪
 * @create: 2020-07-06-16:08
 */
public class StringBuilderTest {
     

    // s1的声明方式是线程安全的,因为是内部产生,内部消亡的
    public static void method01() {
     
        // 线程内部创建的,属于局部变量
        StringBuilder s1 = new StringBuilder();
        s1.append("a");
        s1.append("b");
    }

    // 这个也是线程不安全的,因为有返回值,有可能被其它的程序所调用
    public static StringBuilder method04() {
     
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("a");
        stringBuilder.append("b");
        return stringBuilder;
    }

    // stringBuilder 是线程不安全的,操作的是共享数据
    public static void method02(StringBuilder stringBuilder) {
     
        stringBuilder.append("a");
        stringBuilder.append("b");
    }


    /**
     * 同时并发的执行,会出现线程不安全的问题
     */
    public static void method03() {
     
        StringBuilder stringBuilder = new StringBuilder();
        new Thread(() -> {
     
            stringBuilder.append("a");
            stringBuilder.append("b");
        }, "t1").start();

        method02(stringBuilder);
    }

    // StringBuilder是线程安全的,但是String也可能线程不安全的,以为返回的是String,可能被其他线程调用
    public static String method05() {
     
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("a");
        stringBuilder.append("b");
        return stringBuilder.toString();
    }
}

第六章、本地方法接口

尚硅谷JVM从入门到精通宋红康版|第六章、本地方法接口

P63 63-本地方法接口的理解(先跳出运行数据区讲一下本地方法库)

JVM从入门到精通_第82张图片

JVM从入门到精通_第83张图片
JVM从入门到精通_第84张图片
JVM从入门到精通_第85张图片
JVM从入门到精通_第86张图片
JVM从入门到精通_第87张图片
JVM从入门到精通_第88张图片

P64 64-本地方法栈的理解

JVM从入门到精通_第89张图片
JVM从入门到精通_第90张图片

P65 65-JVM学习路线与内容回顾

第八章、堆(运行时数据区最重要的)

尚硅谷JVM从入门到精通宋红康版|第八章、堆

P66 66-堆空间的概述_进程中堆的唯一性

堆的核心概念

堆针对一个JVM进程来说是唯一的,也就是一个进程只有一个JVM,但是进程包含多个线程,他们是共享同一堆空间的。

一个java 程序运行起来就是一个进程,一个进程对应一个jvm实例,一个jvm实例对应一个运行时数据区,一个运行时数据去对应一个堆和方法区

一个进程包的所有线程是共享同一堆空间和方法区的,每个线程有自己独立的栈、程序计数器、本地方法栈。
JVM从入门到精通_第91张图片
JVM从入门到精通_第92张图片
idea设置java程序运行时堆大小

JVM从入门到精通_第93张图片
JVM从入门到精通_第94张图片

JVM从入门到精通_第95张图片

JVM从入门到精通_第96张图片

运行HeaoDemo java程序

查看运行的堆空间使用情况
下图就是使用:Java VisualVM查看堆空间的内容,通过 jdk bin提供的插件

JVM从入门到精通_第97张图片
JVM从入门到精通_第98张图片
JVM从入门到精通_第99张图片

P67 67-堆空间关于对象创建和和GC的概述

JVM从入门到精通_第100张图片
JVM从入门到精通_第101张图片
JVM从入门到精通_第102张图片

P68 68-堆的细分内存结构

JVM从入门到精通_第103张图片
JVM从入门到精通_第104张图片
JVM从入门到精通_第105张图片

P69 69-堆空间大小的设置和查看

JVM从入门到精通_第106张图片
JVM从入门到精通_第107张图片

  • -Xms 用来设置堆空间(年轻代+老年代)的初始内存大小
  • -X:是jvm运行参数
  • ms:memory start
  • -Xmx:用来设置堆空间(年轻代+老年代)的最大内存大小
/**
 * -Xms 用来设置堆空间(年轻代+老年代)的初始内存大小
 *  -X:是jvm运行参数
 *  ms:memory start
 * -Xmx:用来设置堆空间(年轻代+老年代)的最大内存大小
 *
 * @author: 陌溪
 * @create: 2020-07-06-20:44
 */
public class HeapSpaceInitial {
     
    public static void main(String[] args) {
     
        // 返回Java虚拟机中的堆内存总量
        long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
        // 返回Java虚拟机试图使用的最大堆内存
        long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
        System.out.println("-Xms:" + initialMemory + "M");
        System.out.println("-Xmx:" + maxMemory + "M");
    }
}

JVM从入门到精通_第108张图片

手动设置堆内存
JVM从入门到精通_第109张图片
如何查看堆内存的内存分配情况:

方式一:

先查看当前程序运行进程
JVM从入门到精通_第110张图片

看某个进程内存分配信息:

jps  ->  staat -gc  进程id

在这里插入图片描述
25600+153600+409600=588800/1024=575

25600+25600+153600+409600=614400/1024=600

因为存储的时候s0c和s1c都能放,但有一个始终是空的,所以我们打印的是575(有一个没算),而我们查询内存分配总的是600

方式二:
JVM从入门到精通_第111张图片

即打印gc细节

-XX:+PrintGCDetails

在程序运行结束后打印
JVM从入门到精通_第112张图片

P70 70-OOM的说明与举例

设置堆内存:
JVM从入门到精通_第113张图片

JVM从入门到精通_第114张图片

JVM从入门到精通_第115张图片
JVM从入门到精通_第116张图片

old区已满溢出

我们简单的写一个OOM例子

/**
 * OOM测试
 *
 * @author: 陌溪
 * @create: 2020-07-06-21:11
 */
public class OOMTest {
     
    public static void main(String[] args) {
     
        List<Integer> list = new ArrayList<>();
        while(true) {
     
            list.add(999999999);
        }
    }
}

然后设置启动参数
设置堆内存:

-Xms10m -Xmx:10m

JVM从入门到精通_第117张图片

运行后,就出现OOM了,那么我们可以通过 VisualVM这个工具查看具体是什么参数造成的OOM

P71 71-新生代与老年代中相关参数的设置

JVM从入门到精通_第118张图片
JVM从入门到精通_第119张图片

P72 72-图解对象分配的一般过程

s0和s1谁为空时谁为to
伊甸园(Eden)(《圣经》中亚当和夏娃最初居住的地方)

伊甸园区(Eden)满时触发MinorGC

我们创建的对象,一般都是存放在Eden区的,当我们Eden区满了后,就会触发GC操作,一般被称为 YGC / Minor GC操作

JVM从入门到精通_第120张图片
当我们进行一次垃圾收集后,红色的将会被回收,而绿色的还会被占用着,存放在S0(Survivor From)区。同时我们给每个对象设置了一个年龄计数器,一次回收后就是1。

同时Eden区继续存放对象,当Eden区再次存满的时候,又会触发一个MinorGC操作,此时GC将会把 Eden和Survivor From中的对象 进行一次收集,把存活的对象放到 Survivor To区,同时让年龄 + 1
JVM从入门到精通_第121张图片
我们继续不断的进行对象生成 和 垃圾回收,当Survivor中的对象的年龄达到15的时候,将会触发一次 Promotion晋升的操作,也就是将年轻代中的对象 晋升到 老年代中
JVM从入门到精通_第122张图片

JVM从入门到精通_第123张图片
思考:幸存区区满了后?
特别注意,在Eden区满了的时候,才会触发MinorGC,而幸存者区满了后,不会触发MinorGC操作

如果Survivor区满了后,将会触发一些特殊的规则,也就是可能直接晋升老年代
在这里插入图片描述
一般情况下大部分的对象在Eden区就被MinorGC回收了

P73 73-对象分配的特殊情况、

JVM从入门到精通_第124张图片

P74 74-代码举例与JVisualVM演示对象的分配过程

/**
 * 代码演示对象创建过程
 *
 * @author: 陌溪
 * @create: 2020-07-07-9:16
 */
public class HeapInstanceTest {
     
    byte [] buffer = new byte[new Random().nextInt(1024 * 200)];
    public static void main(String[] args) throws InterruptedException {
     
        ArrayList<HeapInstanceTest> list = new ArrayList<>();
        while (true) {
     
            list.add(new HeapInstanceTest());
            Thread.sleep(10);
        }
    }
}

然后设置JVM参数

-Xms600m -Xmx600m

最终,在老年代和新生代都满了,就出现OOM
JVM从入门到精通_第125张图片

然后cmd输入下面命令,打开VisualVM图形化界面

jvisualvm

然后通过执行上面代码,通过VisualGC进行动态化查看

JVM从入门到精通_第126张图片

P75 75-常用优工具概述与Jprofiler的演示

常用的调优工具

  • JDK命令行
  • Eclipse:Memory Analyzer Tool
  • Jconsole
  • Visual VM(实时监控 推荐~)
  • Jprofiler(推荐~)
  • Java Flight Recorder(实时监控)
  • GCViewer
  • GCEasy
    JVM从入门到精通_第127张图片

P76 76-MinorGC、MajorGC和FullGC的对比

  • Minor GC:新生代的GC
  • Major GC:老年代的GC
  • Full GC:整堆收集,收集整个Java堆和方法区的垃圾收集

我们都知道,JVM的调优的一个环节,也就是垃圾收集,我们需要尽量的避免垃圾回收,因为在垃圾回收的过程中,容易出现STW的问题
而 Major GC 和 Full GC出现STW的时间,是Minor GC的10倍以上,Minor GC会引发STW。
所有jvm调优主要避免GC,调优主要是针对Major GC 和 Full GC

STW: 在进行垃圾回收的时候要暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行,会造成一段时间用户线程不可用。
JVM从入门到精通_第128张图片
JVM从入门到精通_第129张图片

JVM从入门到精通_第130张图片
JVM从入门到精通_第131张图片
JVM从入门到精通_第132张图片

JVM从入门到精通_第133张图片

P77 77-GC举例与日志分析

我们编写一个OOM的异常,因为我们在不断的创建字符串,是存放在元空间的

/**
 * GC测试
 *
 * @author: 陌溪
 * @create: 2020-07-07-10:01
 */
public class GCTest {
     
    public static void main(String[] args) {
     
        int i = 0;
        try {
     
            List<String> list = new ArrayList<>();
            String a = "mogu blog";
            while(true) {
     
                list.add(a);
                a = a + a;
                i++; 
            }
        }catch (Exception e) {
     
            e.getStackTrace();
        }
    }
}

设置JVM启动参数

-Xms10m -Xmx10m -XX:+PrintGCDetails

打印出的日志
JVM从入门到精通_第134张图片

[GC (Allocation Failure) [PSYoungGen: 2038K->500K(2560K)] 2038K->797K(9728K), 0.3532002 secs] [Times: user=0.01 sys=0.00, real=0.36 secs] 
[GC (Allocation Failure) [PSYoungGen: 2108K->480K(2560K)] 2405K->1565K(9728K), 0.0014069 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2288K->0K(2560K)] [ParOldGen: 6845K->5281K(7168K)] 9133K->5281K(9728K), [Metaspace: 3482K->3482K(1056768K)], 0.0058675 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 5281K->5281K(9728K), 0.0002857 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 5281K->5263K(7168K)] 5281K->5263K(9728K), [Metaspace: 3482K->3482K(1056768K)], 0.0058564 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 2560K, used 60K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 2% used [0x00000000ffd00000,0x00000000ffd0f138,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 7168K, used 5263K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
  object space 7168K, 73% used [0x00000000ff600000,0x00000000ffb23cf0,0x00000000ffd00000)
 Metaspace       used 3514K, capacity 4498K, committed 4864K, reserved 1056768K
  class space    used 388K, capacity 390K, committed 512K, reserved 1048576K
  
  Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOfRange(Arrays.java:3664)
	at java.lang.String.<init>(String.java:207)
	at java.lang.StringBuilder.toString(StringBuilder.java:407)
	at com.atguigu.java.chapter08.GCTest.main(GCTest.java:20)

P78 78-体会堆空间分代的思想

JVM从入门到精通_第135张图片
JVM从入门到精通_第136张图片

P79 79-总结堆内存分配策略

JVM从入门到精通_第137张图片
JVM从入门到精通_第138张图片
大对象直接到老年区举例:
JVM从入门到精通_第139张图片
JVM从入门到精通_第140张图片

P80 80-堆空间为每个线程分配的TLAB

问题:堆空间都是共享的么?

不一定,因为还有TLAB这个概念,在堆中划分出一块区域,为每个线程所独占

JVM从入门到精通_第141张图片
JVM从入门到精通_第142张图片

JVM从入门到精通_第143张图片
JVM从入门到精通_第144张图片
JVM从入门到精通_第145张图片
查看tlab是否开启
JVM从入门到精通_第146张图片
对于单个线程TLAB分配过程:
对象首先是通过TLAB开辟空间,如果不能放入,那么需要通过Eden来进行分配
JVM从入门到精通_第147张图片

P81 81-小结堆空间的常用参数设置(面试常问,查看你是否在实际项目中使用过)

jvm堆空间常用参数:

官网:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
JVM从入门到精通_第148张图片
JVM从入门到精通_第149张图片

在发生Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象的总空间:
JVM从入门到精通_第150张图片

P82 82-通过逃逸分析看堆空间的对象分配策略

逃逸分析:对象的使用作用域是否超出一个方法。
如果对象的使用作用域只在一个方法内,就可以把此对象分配到堆上。
JVM从入门到精通_第151张图片
JVM从入门到精通_第152张图片
JVM从入门到精通_第153张图片
JVM从入门到精通_第154张图片
完整的逃逸分析代码举例

/**
 * 逃逸分析
 * 如何快速的判断是否发生了逃逸分析,大家就看new的对象是否在方法外被调用。
 * @author: 陌溪
 * @create: 2020-07-07-20:05
 */
public class EscapeAnalysis {
     

    public EscapeAnalysis obj;

    /**
     * 方法返回EscapeAnalysis对象,发生逃逸
     * @return
     */
    public EscapeAnalysis getInstance() {
     
        return obj == null ? new EscapeAnalysis():obj;
    }

    /**
     * 为成员属性赋值,发生逃逸
     */
    public void setObj() {
     
        this.obj = new EscapeAnalysis();
    }

    /**
     * 对象的作用于仅在当前方法中有效,没有发生逃逸
     */
    public void useEscapeAnalysis() {
     
        EscapeAnalysis e = new EscapeAnalysis();
    }

    /**
     * 引用成员变量的值,发生逃逸
     */
    public void useEscapeAnalysis2() {
     
        EscapeAnalysis e = getInstance();
        // getInstance().XXX  发生逃逸
    }
}

JVM从入门到精通_第155张图片
在这里插入图片描述

P83 83-代码优化之栈上分配

JVM从入门到精通_第156张图片
**栈上分配: **
JVM从入门到精通_第157张图片
举例
我们通过举例来说明 开启逃逸分析 和 未开启逃逸分析时候的情况

/**
 * 栈上分配
 * -Xmx1G -Xms1G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails
 * @author: 陌溪
 * @create: 2020-07-07-20:23
 */
class User {
     
    private String name;
    private String age;
    private String gender;
    private String phone;
}
public class StackAllocation {
     
    public static void main(String[] args) throws InterruptedException {
     
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
     
            alloc();
        }
        long end = System.currentTimeMillis();
        System.out.println("花费的时间为:" + (end - start) + " ms");

        // 为了方便查看堆内存中对象个数,线程sleep
        Thread.sleep(10000000);
    }

    private static void alloc() {
     
        User user = new User();
    }
}

设置JVM参数,表示未开启逃逸分析

-XX:-DoEscapeAnalysis 关闭逃逸分析

-Xmx1G -Xms1G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails

运行结果,同时还触发了GC操作

花费的时间为:664 ms

JVM从入门到精通_第158张图片
我们在开启逃逸分析(-号改成+号:开启逃逸分析)

-XX:+DoEscapeAnalysis 开启逃逸分析

-Xmx1G -Xms1G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails

然后查看运行时间,我们能够发现花费的时间快速减少,同时不会发生GC操作

花费的时间为:5 ms

然后在看内存情况,我们发现只有很少的User对象,说明User发生了逃逸,因为他们存储在栈中,随着栈的销毁而消失

JVM从入门到精通_第159张图片

P84 84-代码优化之同步省略

同步省略:如果一个对象被发现只有一个线程被访问到,那么对于这个对象的操作可以不考虑同步。

JVM从入门到精通_第160张图片
JVM从入门到精通_第161张图片

P85 85-代码优化之标量替换

分离对象或标量替换:有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。

标量替换: 就是把对象打散了分配到栈上
JVM从入门到精通_第162张图片

public static void main(String args[]) {
     
    alloc();
}
class Point {
     
    private int x;
    private int y;
} 
private static void alloc() {
     
    Point point = new Point(1,2);
    System.out.println("point.x" + point.x + ";point.y" + point.y);
}

以上代码,经过标量替换后,就会变成

private static void alloc() {
     
    int x = 1;
    int y = 2;
    System.out.println("point.x = " + x + "; point.y=" + y);
}

可以看到,Point这个聚合量经过逃逸分析后,发现他并没有逃逸,就被替换成两个聚合量了。那么标量替换有什么好处呢?就是可以大大减少堆内存的占用。因为一旦不需要创建对象了,那么就不再需要分配堆内存了。
标量替换为栈上分配提供了很好的基础。

JVM从入门到精通_第163张图片

P86 86-代码优化及堆的小结

JVM从入门到精通_第164张图片
在这里插入图片描述

在这里插入图片描述

第九章、方法区

尚硅谷JVM从入门到精通宋红康版|第九章、方法区

方法区主要存放的是 类(Class)信息,而堆中主要存放的是 实例化的对象

P87 87-方法区概述_栈堆方法区间的交互关系

JVM从入门到精通_第165张图片

JVM从入门到精通_第166张图片
JVM从入门到精通_第167张图片

栈、堆、方法区的交互关系

Person:存放在元空间,也可以说方法区
person:存放在Java栈的局部变量表中
new Person():存放在Java堆中
JVM从入门到精通_第168张图片

P88 88-方法区的基本理解

JVM从入门到精通_第169张图片
方法区主要存放的是 类(Class)信息,而堆中主要存放的是 实例化的对象
JVM从入门到精通_第170张图片
JVM从入门到精通_第171张图片

P89 89-Hotspot中方法区的演进

JVM从入门到精通_第172张图片
JVM从入门到精通_第173张图片

P90 90-设置方法区大小的参数

JVM从入门到精通_第174张图片

JVM从入门到精通_第175张图片

P91 91-OOM:PermGen和OOM:Metaspace举例

JVM从入门到精通_第176张图片
JVM从入门到精通_第177张图片

在这里插入图片描述

JVM从入门到精通_第178张图片
JVM从入门到精通_第179张图片

P92 92-方法区的内部结构1

JVM从入门到精通_第180张图片
JVM从入门到精通_第181张图片
JVM从入门到精通_第182张图片
JVM从入门到精通_第183张图片
JVM从入门到精通_第184张图片

P93 93-方法区的内部结构2

JVM从入门到精通_第185张图片

/**
 * non-final的类变量
 *
 * @author: 陌溪
 * @create: 2020-07-08-16:54
 */
public class MethodAreaTest {
     
    public static void main(String[] args) {
     
        Order order = new Order();
        //Order order = null;
        order.hello();
        System.out.println(order.count);
    }
}
class Order {
     
    public static int count = 1;
    public static final int number = 2;
    public static void hello() {
     
        System.out.println("hello!");
    }
}

如上代码所示,即使我们把order设置为null,也不会出现空指针异常

P94 94-class文件中常量池的理解

JVM从入门到精通_第186张图片

P95 95-运行时常量池的理解
P96 96-图示举例方法区的使用

P97 97-方法区在jdk6、jdk7、jdk8中的演进细节

方法区的演进细节
首先明确:只有Hotspot才有永久代。BEA JRockit、IBMJ9等来说,是不存在永久代的概念的。原则上如何实现方法区属于虚拟机实现细节,不受《Java虚拟机规范》管束,并不要求统一

Hotspot中方法区的变化:
在这里插入图片描述
JDK7的时候
JVM从入门到精通_第187张图片
JDK8的时候,元空间大小只受物理内存影响
JVM从入门到精通_第188张图片
JVM从入门到精通_第189张图片

P98 98-StringTable为什么要调整位置
P99 99-如何证明静态变量存在哪
P100 100-方法区的垃圾回收行为
P101 101-运行时数据区的总结与常见大厂面试题说明
P102 102-对象实例化的几种方式
P103 103-字节码角度看对象的创建过程
P104 104-对象创建的六个步骤
P105 105-对象的内存布局
P106 106-对象访问定位
P107 107-直接内存的简单体验
P108 108-使用本地内存读写数据的测试
P109 109-直接内存的00M与内存大小的设置

执行引擎

P110 110-执行引擎的作用及工作过程概述
P111 111-Java程序的编译和解释运行的理解
P112 112-机器码_指令_汇编_高级语言理解与执行过程
P113 113-解释器的使用
P114 114-HotspotVM为何解释器与JIT编译器并存
P115 115-热点代码探测确定何时JIT
P116 116-Hotspot设置模式_C1与C2编译器
P117 117-Graal编译器与AOT编译器

StringTable

P118 118-String的不可变性
P119 119-String底层Hashtable结构的说明
P120 120-String内存结构的分配位置
P121 121-两个案例熟悉String的基本操作
P122 122-字符串拼接操作的面试题讲解
P123 123-字符串变量拼接操作的底层原理
P124 124-拼接操作与append操作的效率对比
P125 125-intern()的理解
P126 126-new String()到底创建了几个对象
P127 127-关于intern()的面试难题
P128 128-面试的拓展问题
P129 129-intern()的课后练习1
P130 130-intern()的课后练习2
P131 131-intern()的空间效率测试
P132 132-StringTable的垃圾回收测试

P133 133-G1垃圾收集器的String去重操作

第十四章、垃圾回收概述

尚硅谷JVM从入门到精通宋红康版|第十四章、垃圾回收概述

P134 134-垃圾回收相关章节的说明

垃圾回收大厂面试题
蚂蚁金服
你知道哪几种垃圾回收器,各自的优缺点,重点讲一下cms和G1?
JVM GC算法有哪些,目前的JDK版本采用什么回收算法?
G1回收器讲下回收过程GC是什么?为什么要有GC?
GC的两种判定方法?CMS收集器与G1收集器的特点
百度
说一下GC算法,分代回收说下
垃圾收集策略和算法
天猫
JVM GC原理,JVM怎么回收内存
CMS特点,垃圾回收算法有哪些?各自的优缺点,他们共同的缺点是什么?
滴滴
Java的垃圾回收器都有哪些,说下g1的应用场景,平时你是如何搭配使用垃圾回收器的

京东
你知道哪几种垃圾收集器,各自的优缺点,重点讲下cms和G1,
包括原理,流程,优缺点。垃圾回收算法的实现原理
阿里
讲一讲垃圾回收算法。
什么情况下触发垃圾回收?
如何选择合适的垃圾收集算法?
JVM有哪三种垃圾回收器?
字节跳动
常见的垃圾回收器算法有哪些,各有什么优劣?
System.gc()和Runtime.gc()会做什么事情?
Java GC机制?GC Roots有哪些?
Java对象的回收方式,回收算法。
CMS和G1了解么,CMS解决什么问题,说一下回收的过程。
CMS回收停顿了几次,为什么要停顿两次?

  • 什么是垃圾?
    JVM从入门到精通_第190张图片

P135 135-什么是GC,为什么需要GC

JVM从入门到精通_第191张图片

P136 136-了解早期垃圾回收行为

JVM从入门到精通_第192张图片
JVM从入门到精通_第193张图片

P137 137-Java自动内存管理介绍

Java垃圾回收机制 ,优点:
JVM从入门到精通_第194张图片
Java垃圾回收机制 ,担忧:
JVM从入门到精通_第195张图片

GC主要关注的区域
GC主要关注于 方法区 和堆中的垃圾收集
JVM从入门到精通_第196张图片

第十五章、垃圾收集相关算法(面试常问)

P138 138-垃圾回收相关算法概述

垃圾回收主要包含连个阶段

  1. 垃圾标记阶段:判断对象存活一般有两种方式:引用计数算法(没有被Java使用)和可达性分析算法。
  2. 垃圾清除阶段
    JVM从入门到精通_第197张图片

1. 垃圾标记阶段

垃圾标记阶段:判断对象存活一般有两种方式:

  1. 引用计数算法(没有被Java使用)
  2. 可达性分析算法。

P139 139-引用计数算法的原理及优缺点(没有被Java使用)

JVM从入门到精通_第198张图片
标记阶段:引用计数算法

JVM从入门到精通_第199张图片
循环引用
当p的指针断开的时候,内部的引用形成一个循环,这就是循环引用,从而造成内存泄漏
JVM从入门到精通_第200张图片
JVM从入门到精通_第201张图片

##P140 140-Java代码举例_Python的引用计数实施方案

P141 141-可达性分析算法与GC Roots

概念
可达性分析算法:也可以称为 根搜索算法、追踪性垃圾收集

标记阶段:可达性分析算法(java使用)

JVM从入门到精通_第202张图片
在这里插入图片描述

JVM从入门到精通_第203张图片
JVM从入门到精通_第204张图片

JVM从入门到精通_第205张图片
JVM从入门到精通_第206张图片
JVM从入门到精通_第207张图片

P142 142-对象的finalization机制

JVM从入门到精通_第208张图片
JVM从入门到精通_第209张图片

由于finalize()方法的存在,虚拟机中的对象一般处于三种可能的状态(面试题)。

JVM从入门到精通_第210张图片
JVM从入门到精通_第211张图片
上图就是我们看到的Finalizer线程

P143 143-代码演示可复活的对象

代码演示
我们使用重写 finalize()方法,然后在方法的内部,重写将其存放到GC Roots中

/**
 * 测试Object类中finalize()方法
 * 对象复活场景
 *
 * @author: 陌溪
 * @create: 2020-07-12-11:06
 */
public class CanReliveObj {
     
    // 类变量,属于GC Roots的一部分
    public static CanReliveObj canReliveObj;

    @Override
    protected void finalize() throws Throwable {
     
        super.finalize();
        System.out.println("调用当前类重写的finalize()方法");
        canReliveObj = this;
    }

    public static void main(String[] args) throws InterruptedException {
     
        canReliveObj = new CanReliveObj();
        canReliveObj = null;
        System.gc();
        System.out.println("-----------------第一次gc操作------------");
        // 因为Finalizer线程的优先级比较低,暂停2秒,以等待它
        Thread.sleep(2000);
        if (canReliveObj == null) {
     
            System.out.println("obj is dead");
        } else {
     
            System.out.println("obj is still alive");
        }

        System.out.println("-----------------第二次gc操作------------");
        canReliveObj = null;
        System.gc();
        // 下面代码和上面代码是一样的,但是 canReliveObj却自救失败了
        Thread.sleep(2000);
        if (canReliveObj == null) {
     
            System.out.println("obj is dead");
        } else {
     
            System.out.println("obj is still alive");
        }

    }
}

最后运行结果



-----------------第一次gc操作------------
调用当前类重写的finalize()方法
obj is still alive
-----------------第二次gc操作------------
obj is dead

在进行第一次清除的时候,我们会执行finalize方法,然后 对象 进行了一次自救操作,但是因为finalize()方法只会被调用一次,因此第二次该对象将会被垃圾清除。

P144 144-使用MAT查看GC Roots

MAT是什么?
MAT是Memory Analyzer的简称,它是一款功能强大的Java堆内存分析器。用于查找内存泄漏以及查看内存消耗情况。

MAT是基于Eclipse开发的,是一款免费的性能分析工具。

大家可以在http://www.eclipse.org/mat/下载并使用MAT

使用命令行 jmap 生成Dump文件
JVM从入门到精通_第212张图片

P145 145-使用JProfiler进行GC Roots溯源(主要是为了查找导致内存泄漏的对象)

JProfiler的GC Roots溯源
我们在实际的开发中,一般不会查找全部的GC Roots,可能只是查找某个对象的整个链路,或者称为GC Roots溯源,这个时候,我们就可以使用JProfiler

可以直接安装运行也可以在IDEA安装Jprofiler插件
在这里插入图片描述

JVM从入门到精通_第213张图片

JVM从入门到精通_第214张图片

P146 146-使用JProfiler分析OOM

当我们程序出现OOM的时候,我们就需要进行排查,我们首先使用下面的例子进行说明
JVM从入门到精通_第215张图片

/**
 * 内存溢出排查
 * -Xms8m -Xmx8m -XX:HeapDumpOnOutOfMemoryError
 * @author: 陌溪
 * @create: 2020-07-12-14:56
 */
public class HeapOOM {
     
    // 创建1M的文件
    byte [] buffer = new byte[1 * 1024 * 1024];

    public static void main(String[] args) {
     
        ArrayList<HeapOOM> list = new ArrayList<>();
        int count = 0;
        try {
     
            while (true) {
     
                list.add(new HeapOOM());
                count++;
            }
        } catch (Exception e) {
     
            e.getStackTrace();
            System.out.println("count:" + count);
        }
    }
}

上述代码就是不断的创建一个1M小字节数组,然后让内存溢出,我们需要限制一下内存大小,同时使用HeapDumpOnOutOfMemoryError将出错时候的dump文件输出

-Xms8m -Xmx8m -XX:HeapDumpOnOutOfMemoryError

我们将生成的dump文件打开,然后点击Biggest Objects就能够看到超大对象
JVM从入门到精通_第216张图片

JVM从入门到精通_第217张图片

JVM从入门到精通_第218张图片
JVM从入门到精通_第219张图片

然后我们通过线程,还能够定位到哪里出现OOM

2. 清除阶段

JVM从入门到精通_第220张图片

P147 147-标记-清除算法原理及优缺点

JVM从入门到精通_第221张图片
JVM从入门到精通_第222张图片
JVM从入门到精通_第223张图片

P148 148-复制算法原理及优缺点

JVM从入门到精通_第224张图片
JVM从入门到精通_第225张图片
JVM从入门到精通_第226张图片

JVM从入门到精通_第227张图片

P149 149-标记-压缩算法原理及优缺点

JVM从入门到精通_第228张图片
JVM从入门到精通_第229张图片
JVM从入门到精通_第230张图片
JVM从入门到精通_第231张图片

P150 150-不同指标上对比三种算法

JVM从入门到精通_第232张图片

P151 151-分代收集算法的说明

JVM从入门到精通_第233张图片
JVM从入门到精通_第234张图片
JVM从入门到精通_第235张图片

P152 152-增量收集算法原理及优缺点

JVM从入门到精通_第236张图片
JVM从入门到精通_第237张图片

P153 153-分区算法的说明

JVM从入门到精通_第238张图片

JVM从入门到精通_第239张图片
在这里插入图片描述

第十六章、垃圾回收相关概念

P154 154-垃圾回收相关概念的概述

P155 155-System.gc()的理解

JVM从入门到精通_第240张图片
JVM从入门到精通_第241张图片
JVM从入门到精通_第242张图片
JVM从入门到精通_第243张图片
JVM从入门到精通_第244张图片
代码演示是否出发GC操作

/**
 * System.gc()
 *
 * @author: 陌溪
 * @create: 2020-07-12-19:07
 */
public class SystemGCTest {
     
    public static void main(String[] args) {
     
        new SystemGCTest();
        // 提醒JVM进行垃圾回收
        System.gc();
        //System.runFinalization();
    }

    @Override
    protected void finalize() throws Throwable {
     
        super.finalize();
        System.out.println("SystemGCTest 执行了 finalize方法");
    }
}

JVM从入门到精通_第245张图片
即如果调用 System.gc();不一定会触发finalize方法,打印SystemGCTest 执行了 finalize方法,而如果调用System.runFinalization()会强制调用,并打印

运行结果,但是不一定会触发销毁的方法,调用System.runFinalization()会强制调用 失去引用对象的finalize()

/**
 * System.gc()
 *
 * @author: 陌溪
 * @create: 2020-07-12-19:07
 */
public class SystemGCTest {
     
    public static void main(String[] args) {
     
        new SystemGCTest();
        // 提醒JVM进行垃圾回收
        System.gc();
        //System.runFinalization();
    }

    @Override
    protected void finalize() throws Throwable {
     
        super.finalize();
        System.out.println("SystemGCTest 执行了 finalize方法");
    }
}

P156 156-手动gc理解不可达对象的回收行为

P157 157-内存溢出的分析

JVM从入门到精通_第246张图片
JVM从入门到精通_第247张图片
JVM从入门到精通_第248张图片

P158 158-内存泄漏的分析

JVM从入门到精通_第249张图片

java使用的是可达性分析算法,内存泄漏都是针对可达性分析算法说的
JVM从入门到精通_第250张图片
内存泄漏举例:
JVM从入门到精通_第251张图片

P159 159-StopTheWorld事件的理解

JVM从入门到精通_第252张图片
JVM从入门到精通_第253张图片

P160 160-程序的并行与并发

JVM从入门到精通_第254张图片
并行要求cpu是多核
JVM从入门到精通_第255张图片
JVM从入门到精通_第256张图片

P161 161-垃圾回收的并行与并发

JVM从入门到精通_第257张图片
JVM从入门到精通_第258张图片

P162 162-安全点与安全区域的说明

JVM从入门到精通_第259张图片
面试会问:
JVM从入门到精通_第260张图片
JVM从入门到精通_第261张图片
JVM从入门到精通_第262张图片

P163 163-Java中几种不同引用的概述(面试题)

JVM从入门到精通_第263张图片
JVM从入门到精通_第264张图片

P164 164-强引用:不回收

JVM从入门到精通_第265张图片
举例
强引用的案例说明

StringBuffer str = new StringBuffer("hello mogublog");

局部变量str指向stringBuffer实例所在堆空间,通过str可以操作该实例,那么str就是stringBuffer实例的强引用对应内存结构:
JVM从入门到精通_第266张图片

如果此时,在运行一个赋值语句

StringBuffer str = new StringBuffer("hello mogublog");
StringBuffer str1 = str;

对应的内存结构为:
JVM从入门到精通_第267张图片

那么我们将 str = null; 则 原来堆中的对象也不会被回收,因为还有其它对象指向该区域
JVM从入门到精通_第268张图片

P165 165-软引用:内存不足即回收

在这里插入图片描述
注意,这里的第一次回收是不可达的对象
JVM从入门到精通_第269张图片

// 声明强引用
Object obj = new Object();
// 创建一个软引用
SoftReference<Object> sf = new SoftReference<>(obj);
obj = null; //销毁强引用,这是必须的,不然会存在强引用和软引用

JVM从入门到精通_第270张图片

P166 166-弱引用:发现即回收

JVM从入门到精通_第271张图片

P167 167-虚引用:对象回收跟踪

JVM从入门到精通_第272张图片
JVM从入门到精通_第273张图片

// 声明强引用
Object obj = new Object();
// 声明引用队列
ReferenceQueue phantomQueue = new ReferenceQueue();
// 声明虚引用(还需要传入引用队列)
PhantomReference<Object> sf = new PhantomReference<>(obj, phantomQueue);
obj = null; 

案例
我们使用一个案例,来结合虚引用,引用队列,finalize进行讲解

/**
 * @author: 陌溪
 * @create: 2020-07-12-21:42
 */
public class PhantomReferenceTest {
     
    // 当前类对象的声明
    public static PhantomReferenceTest obj;
    // 引用队列
    static ReferenceQueue<PhantomReferenceTest> phantomQueue = null;

    @Override
    protected void finalize() throws Throwable {
     
        super.finalize();
        System.out.println("调用当前类的finalize方法");
        obj = this;
    }

    public static void main(String[] args) {
     
        Thread thread = new Thread(() -> {
     
            while(true) {
     
                if (phantomQueue != null) {
     
                    PhantomReference<PhantomReferenceTest> objt = null;
                    try {
     
                        objt = (PhantomReference<PhantomReferenceTest>) phantomQueue.remove();
                    } catch (Exception e) {
     
                        e.getStackTrace();
                    }
                    if (objt != null) {
     
                        System.out.println("追踪垃圾回收过程:PhantomReferenceTest实例被GC了");
                    }
                }
            }
        }, "t1");
        thread.setDaemon(true);
        thread.start();

        phantomQueue = new ReferenceQueue<>();
        obj = new PhantomReferenceTest();
        // 构造了PhantomReferenceTest对象的虚引用,并指定了引用队列
        PhantomReference<PhantomReferenceTest> phantomReference = new PhantomReference<>(obj, phantomQueue);
        try {
     
            System.out.println(phantomReference.get());
            // 去除强引用
            obj = null;
            // 第一次进行GC,由于对象可复活,GC无法回收该对象
            System.out.println("第一次GC操作");
            System.gc();
            Thread.sleep(1000);
            if (obj == null) {
     
                System.out.println("obj 是 null");
            } else {
     
                System.out.println("obj 不是 null");
            }
            System.out.println("第二次GC操作");
            obj = null;
            System.gc();
            Thread.sleep(1000);
            if (obj == null) {
     
                System.out.println("obj 是 null");
            } else {
     
                System.out.println("obj 不是 null");
            }
        } catch (Exception e) {
     
            e.printStackTrace();
        } finally {
     

        }
    }
}

最后运行结果

null
第一次GC操作
调用当前类的finalize方法
obj 不是 null
第二次GC操作
追踪垃圾回收过程:PhantomReferenceTest实例被GC了
obj 是 null

P168 168-终结器引用的介绍(了解即可)

第十七章、垃圾回收器

P169 169-垃圾回收器章节概览

JVM从入门到精通_第274张图片
Java不同版本新特性

语法层面:Lambda表达式、switch、自动拆箱装箱、enum
API层面:Stream API、新的日期时间、Optional、String、集合框架
底层优化:JVM优化、GC的变化、元空间、静态域、字符串常量池位置变化

P170 170-垃圾回收器的分类

  1. 按线程数分
    按线程数分(垃圾回收线程数),可以分为串行垃圾回收器和并行垃圾回收器。
    JVM从入门到精通_第275张图片
    JVM从入门到精通_第276张图片
  2. 按工作模式分
    按照工作模式分,可以分为并发式垃圾回收器和独占式垃圾回收器。

JVM从入门到精通_第277张图片
JVM从入门到精通_第278张图片

P171 171-GC性能指标的整体说明

JVM从入门到精通_第279张图片
JVM从入门到精通_第280张图片

P172 172-吞吐量与暂停时间的对比说明

现在标准:在最大吞吐量优先的情况下,降低停顿时间

性能指标:吞吐量
JVM从入门到精通_第281张图片
性能指标:暂停时间
JVM从入门到精通_第282张图片
JVM从入门到精通_第283张图片

JVM从入门到精通_第284张图片
JVM从入门到精通_第285张图片

P173 173-垃圾回收器的发展迭代史

JVM从入门到精通_第286张图片
GC垃圾收集器是和JVM一脉相承的,它是和JVM进行搭配使用,在不同的使用场景对应的收集器也是有区别
JVM从入门到精通_第287张图片

JVM从入门到精通_第288张图片
serial parNew parallel scavenge

7种经典的垃圾收集器
JVM从入门到精通_第289张图片
JVM从入门到精通_第290张图片

P174 174-垃圾回收器的组合关系

JVM从入门到精通_第291张图片
JVM从入门到精通_第292张图片
JVM从入门到精通_第293张图片
JVM从入门到精通_第294张图片

P175 175-如何查看默认的垃圾回收器

-XX:+PrintcommandLineFlags:查看命令行相关参数(包含使用的垃圾收集器)

使用命令行指令:jinfo -flag 相关垃圾回收器参数 进程ID

JVM从入门到精通_第295张图片

JVM从入门到精通_第296张图片

P176 176-Serial与Serial Old垃圾回收器的介绍(基本不用,了解即可)

Serial与Serial Old垃圾回收器主要用于单核CPU的场景
JVM从入门到精通_第297张图片
JVM从入门到精通_第298张图片

JVM从入门到精通_第299张图片

P177 177-如何设置使用Serial垃圾回收器

在HotSpot虚拟机中,使用-XX:+UseSerialGC参数可以指定年轻代和老年代都使用串行收集器。

等价于新生代用Serial GC,且老年代用Serial old GC
在这里插入图片描述

在这里插入图片描述
JVM从入门到精通_第300张图片

P178 178-ParNew垃圾回收器的介绍

JVM从入门到精通_第301张图片

JVM从入门到精通_第302张图片
JVM从入门到精通_第303张图片
JVM从入门到精通_第304张图片

P179 179-如何设置使用ParNew垃圾回收器

P180 180-Parallel与Parallel Old垃圾回收器的介绍

Parallel与Parallel Old垃圾回收器 :吞吐量优先
JVM从入门到精通_第305张图片
JVM从入门到精通_第306张图片
在这里插入图片描述

P181 181-Parallel垃圾回收器的相关参数设置

JVM从入门到精通_第307张图片
JVM从入门到精通_第308张图片
JVM从入门到精通_第309张图片
JVM从入门到精通_第310张图片

P182 182-CMS垃圾回收器概述与工作原理

JVM从入门到精通_第311张图片
JVM从入门到精通_第312张图片
JVM从入门到精通_第313张图片
JVM从入门到精通_第314张图片
JVM从入门到精通_第315张图片

P183 183-CMS的特点与弊端分析

JVM从入门到精通_第316张图片

JVM从入门到精通_第317张图片
JVM从入门到精通_第318张图片

P184 184-CMS垃圾回收器的参数设置

JVM从入门到精通_第319张图片

JVM从入门到精通_第320张图片
JVM从入门到精通_第321张图片

P185 185-CMS的小结及后续JDK版本中的变化

JVM从入门到精通_第322张图片
JVM从入门到精通_第323张图片

P186 186-认识G1垃圾回收器

JVM从入门到精通_第324张图片
JVM从入门到精通_第325张图片
JVM从入门到精通_第326张图片

P187 187-G1垃圾回收器的优势和不足

JVM从入门到精通_第327张图片
JVM从入门到精通_第328张图片
JVM从入门到精通_第329张图片
JVM从入门到精通_第330张图片
JVM从入门到精通_第331张图片

P188 188-G1的参数设置

JVM从入门到精通_第332张图片

JVM从入门到精通_第333张图片

P189 189-G1在生产环境的适用场景

JVM从入门到精通_第334张图片

P190 190-region的使用介绍

JVM从入门到精通_第335张图片

JVM从入门到精通_第336张图片
JVM从入门到精通_第337张图片

JVM从入门到精通_第338张图片

P191 191-G1垃圾回收器的主要回收环节

JVM从入门到精通_第339张图片
JVM从入门到精通_第340张图片
JVM从入门到精通_第341张图片

JVM从入门到精通_第342张图片

P192 192-记忆集与写屏障

JVM从入门到精通_第343张图片

JVM从入门到精通_第344张图片

P193 193-G1垃圾回收过程的详细说明

JVM从入门到精通_第345张图片
JVM从入门到精通_第346张图片
JVM从入门到精通_第347张图片
JVM从入门到精通_第348张图片
JVM从入门到精通_第349张图片
JVM从入门到精通_第350张图片
JVM从入门到精通_第351张图片

P194 194-G1垃圾回收的优化建议

JVM从入门到精通_第352张图片
JVM从入门到精通_第353张图片

P195 195-7种经典的垃圾回收器总结与调优建议

JVM从入门到精通_第354张图片
JVM从入门到精通_第355张图片

JVM从入门到精通_第356张图片
JVM从入门到精通_第357张图片
JVM从入门到精通_第358张图片
JVM从入门到精通_第359张图片

P196 196-常用的显示GC日志的参数

JVM从入门到精通_第360张图片

JVM从入门到精通_第361张图片

JDK8默认垃圾回收器: 年轻代用parallel scavege,老年代用parallel old

JVM从入门到精通_第362张图片
JVM从入门到精通_第363张图片

JVM从入门到精通_第364张图片
JVM从入门到精通_第365张图片
JVM从入门到精通_第366张图片

JVM从入门到精通_第367张图片
JVM从入门到精通_第368张图片

方法区在jdk1.7的落地实现叫永久代,在jdk1.8的落地实现叫元空间

JDK9默认垃圾回收器:G1
JVM从入门到精通_第369张图片
JVM从入门到精通_第370张图片

JVM从入门到精通_第371张图片
JVM从入门到精通_第372张图片
JVM从入门到精通_第373张图片

P197 197-GC日志中垃圾回收数据的分析

JVM从入门到精通_第374张图片

在这里插入图片描述

JVM从入门到精通_第375张图片
JVM从入门到精通_第376张图片
JVM从入门到精通_第377张图片

GC:
JVM从入门到精通_第378张图片
Full GC
JVM从入门到精通_第379张图片

P198 198-举例说明日志中堆空间数据如何解读

JVM从入门到精通_第380张图片
JVM从入门到精通_第381张图片

JVM从入门到精通_第382张图片
JVM从入门到精通_第383张图片
JDK1.7 JDK1.7对于新来的新生代edno区剩余空间放不下的大对象,会将endo的对象全部放到老年代,把新来的大对象再放到endo区
JVM从入门到精通_第384张图片

GC后

JVM从入门到精通_第385张图片

jdk1.8 JDK1.8会将新来的新生代edno区剩余空间放不下的大对象直接放到老年代
JVM从入门到精通_第386张图片
JVM从入门到精通_第387张图片

P199 199-日志分析工具的使用

JVM从入门到精通_第388张图片

在这里插入图片描述
JVM从入门到精通_第389张图片
JVM从入门到精通_第390张图片
JVM从入门到精通_第391张图片

建议使用GCeasy
JVM从入门到精通_第392张图片

P200 200-新时期的Epsilon和Shenandoah垃圾回收器

JVM从入门到精通_第393张图片

P201 201-革命性的ZGC的性能介绍

JVM从入门到精通_第394张图片

JVM从入门到精通_第395张图片

JVM从入门到精通_第396张图片
JVM从入门到精通_第397张图片

P202 202-其他的厂商的垃圾回收器
JVM从入门到精通_第398张图片

你可能感兴趣的:(#,尚硅谷,#,jvm)