JVM知识笔记

在这里插入图片描述

1JVM发展史

在这里插入图片描述
第二种虚拟机:

在这里插入图片描述

2类加载的过程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3运行时数据区

1.PC寄存器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2虚拟机栈

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
设置栈的大小
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这就是为什么不可以再静态方法中用this调用属性,因为slot中没有存放this,也就是在局部变量表中没有这个位置!

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
具体的位置
在这里插入图片描述
在这里插入图片描述

相对于栈结构来说,用寄存器来存储,寄存器的指令更少,执行的速度更快
在这里插入图片描述
在这里插入图片描述

栈帧中的有返回值,局部变量表,操作数栈和指向方法内区运行时常量池的动态连接

方法的调用
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

虚方法指的是类似于晚期绑定,被调用的方法不知道是哪一个类的,故不能在编译器确定下来,就称为虚方法

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

其中areturn表示引用类型的返回

在这里插入图片描述
虚拟机栈内部结构
在这里插入图片描述
在这里插入图片描述

如果局部变量在方法的内部产生,并且在内部消亡,就是线程安全的,但是如果局部变量在方法内部产生。但是返回到方法的外面,其他线程就会有可能抢夺,然后进行修改,从而就是不安全的,故具体问题要具体分析。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

设置堆的大小的指令
Xms10m:设置初始的堆空间的大小为10M
Xmx10m:设置最大的堆空间的大小为10M

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:堆内存的大小=新生区+养老区,暂时不包括元空间

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

新生代老年代空间默认为1:2

在这里插入图片描述

但是实际的新生区中eden区和survivor区的的比例为6:1:1.此原因和自适应的内存分配策略有关
要想改变这个比例,就需要使用 -XX:SurvivorRatio=8指令来改变

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从新生区到老年区的判断次数默认是15次,可以通过以下指令进行修改

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

显示垃圾回收的详细信息

在这里插入图片描述
在这里插入图片描述

堆空间中一定是线程共享的吗?
错误的,堆空间中TLAB是线程私有的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
空间分配担保!但是jdk7之和就变了,默认为true了
在这里插入图片描述
在这里插入图片描述

逃逸分析!

在这里插入图片描述

当其他方法调用下面这个方法时,就会获取返回值,而这个返回值是由对象StringBuffer创建,当使用返回值时,就会用到此对象,故可能会发生了逃逸,所以要在堆中创建,不能使用栈上分配。

在这里插入图片描述

快速判断是否发生了逃逸
就看new的对象实体,是否有可能在方法外面被调用。(不返回就有可能不会发生逃逸)
jdk7
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2同步省略

在这里插入图片描述

3分离对象或者标量替换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法区

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
查看元空间的大小的指令

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
方法区
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行时常量池

在这里插入图片描述

运行时常量池就是在类加载时,把字节码文件中的常量池加载到方法区之后,就变成了运行时常量池

在这里插入图片描述

演进的过程,和为什么要这样呢?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
方法区的垃圾回收
在这里插入图片描述JVM面试题
在这里插入图片描述

对象的内存布局和访问定位

1对象的实例化方式

在这里插入图片描述

2对象的内存布局

在这里插入图片描述例子:假设有一个Customer类,类中有id\name\Account account属性,在customer中已经对属性进行显示赋值后:新建Customer对象时的内存分布如图所示
在这里插入图片描述

3对象访问定位

第一种:引用指针(优点是直接指向对象的位置,hotspot使用)
在这里插入图片描述
第二种:句柄访问(好处是即使对象因为GC赋值和压缩整理算法位置发生了变动,动态链接的指向可以不动,只要句柄池内的指针变动就行)
在这里插入图片描述

执行引擎

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

执行引擎的内部结构

在这里插入图片描述

JIT将整个字节码编译成字节码之后会存放到方法区的缓存中,下次读取时就从缓存中读取,所以就非常的快。

解释器

解释执行就是边翻译为机器码边执行,一条一条地读取字节码,解释并且执行字节码指令。因为它一条一条地解释和执行指令,所以它可以很快地解释字节码,但是执行起来会比较慢,没有JIT的配合下效率不高。

即时编译器JIT(just in time)

即时编译就是先将一个方法中的所有字节码全部编译成机器码之后再执行,即时编译器把整段字节码不加筛选的编译成机器码不论其执行频率是否有编译价值,在程序响应时间的限制下,没有达到最大的优化。
在这里插入图片描述
在这里插入图片描述

结合前面的问题:是不是所有的对象都在堆上分配?其实不是,和逃逸分析有关

混合模式

在HotSpot中默认采用混合模式,其利用解释器先解释执行字节码,然后将其中的热点代码(多次执行,循环等)直接编译成机器码,在使用JIT下次就不用再编译了,直接选中机器码让其更快速地运行。
在这里插入图片描述
在这里插入图片描述

热点代码及探测方式

在这里插入图片描述在这里插入图片描述在这里插入图片描述

知识点扩展

除了JIT编译器之外,还有Graal编译器和AOT编译器
在这里插入图片描述在这里插入图片描述

从AOT编译器的工作过程可以看出,好处时可以提前将字节码转换成机器码,但是缺点是:不符合JAVA中的一次编译到处运行

String Table

在jdk1.8以及之前都是采用char[]数组来存放字符串,而1.9开始,就采用byte[]来存放,并且用编码标记来改变真正存储的结构,比如使用ISO-8859-1时使用byte[]数组,但是使用中文的时使用的仍然是char[]
在这里插入图片描述在这里插入图片描述在这里插入图片描述

为什么要把StringTable从方法区(永久代)放在堆中?
1首先永久代内存比较小,存放的内容不多
2其次是永久代中GC频率较低,产生的String垃圾不能及时清理,容易产生OOM

在这里插入图片描述第一条的验证,常量的拼接时,经过编译优化就直接中常量池中取。所以地址也是同一个地址
在这里插入图片描述
第三条的验证:只要其中有一个是变量,就是在堆中。因为拼接符号的前后出现了变量则相当于在堆空间中new String 具体的内容为拼接的结果。因此会不同
在这里插入图片描述
第四条验证:intern()方法是判断字符串常量池中是否存在字符串,如果存在则返回常量池中字符串的地址,如果不存在则需要在常量池中加载一份判断的字符串,并且返回对象的地址。
在这里插入图片描述

字符串拼接的底层原理

在这里插入图片描述

那是因为s1和s2是final修饰的常量,此时不在是变量

在这里插入图片描述字符串的拼接过程中,使用字符串拼接’+‘要远远慢于StringBuilder的append方法,因为在拼接时+时,就新建一个builder,并且还有toString方法。优化StringBuilder,可以直接对StringBuilder进行初始化长度确定,来减少扩容过程中的时间消耗。

intern()方法

在这里插入图片描述
使用方法:

String s=new String("倔强的加瓦").intern();

如何保证变量s指向的字符串就是常量池中的数据的两种方法

  1. 直接利用字面量进行复制,String s=“倔强的加瓦”;
  2. 使用intern方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第一个全是false,因为s是栈中指向堆空间中new
String的地址,而s2是因为常量池中已经存在,所以之间返回的是常量池中的地址,所以不是同一个地址
第二个在jdk6中为false,是因为字符串常量池在永久代中,不在堆中,所以s3就是一个栈中指向堆中的地址,通过intern方法放到字符串常量池中,s4指向的是子符串常量池中“11”的地址,所以为false.
第二个在jdk7及以后,字符串常量池在堆中,当执行了intern方法时,为了省空间,不会在字符串常量池中新建一个“11”,而是在字符串常量池中,“11”的地址指向的是堆中new String的s3的地址,所以s4虽然指向了字符串常量池中“11”的地址,但是11的地址指向s3所指向的地址,所以为同一个地址故为true

在这里插入图片描述在这里插入图片描述小练习:
在这里插入图片描述

垃圾回收机制

1什么是垃圾:
垃圾是指在运行的程序中没有任何指针指向的对象,这个对象就是需要回收的垃圾。
在这里插入图片描述
在这里插入图片描述

标记阶段

在标记阶段有两种算法:1引用计数算法2可达性分析算法
1 引用计数算法,Java中并没用使用这个算法。。。python使用了这个方法
在这里插入图片描述
2可达性分析算法(或根搜索算法、追踪性垃圾收集)
在这里插入图片描述在这里插入图片描述在这里插入图片描述
roots的判断在这里插入图片描述
finalize方法的存在导致对象有三种状态
在这里插入图片描述在这里插入图片描述

清除阶段

三种算法:
1标记清除Mark-Sweep

在这里插入图片描述
在这里插入图片描述清除只是把需要清除的对象地址保存,当写入时,直接可以在这上面进行覆盖数据,从而达到清除的效果。

2复制算法
在这里插入图片描述在这里插入图片描述复制算法流程图,每次将值复制到新的一片空间中,从而可以保证存储空间的连续性
在这里插入图片描述
3标记-压缩Mark-Compact算法
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

三种算法的比较

在这里插入图片描述

分代算法

在这里插入图片描述

分代收集算法

在这里插入图片描述在这里插入图片描述为了减少STW时间,一种名为增量收集算法使用

在这里插入图片描述在这里插入图片描述分区算法,也是为了降低STW时间
在这里插入图片描述

垃圾回收相关的概念

System.gc()方法的理解

在这里插入图片描述

当调用gc方法时,不一定立马就会开始GC,验证方法是调用gc后,重写finalize()方法,里面的代码不一定执行。
但是有一个方法可以立马执行GC,System.runFinalization()会强制调用使用引用对象的finalize()方法。

内存溢出

在这里插入图片描述在这里插入图片描述在这里插入图片描述

内存泄漏

在这里插入图片描述在这里插入图片描述

Stop-The-World

在这里插入图片描述在这里插入图片描述

垃圾回收的并行和并发

在这里插入图片描述
在这里插入图片描述在这里插入图片描述安全点
在这里插入图片描述在这里插入图片描述安全区域

在这里插入图片描述在安全区域内的实际执行

在这里插入图片描述

引用

在这里插入图片描述在这里插入图片描述
1.强引用—只要有引用,报oom也不回收
在这里插入图片描述在这里插入图片描述在这里插入图片描述2.软引用–内存够时不回收,内存不足即使还有引用也要回收
在这里插入图片描述在这里插入图片描述3弱引用-发现就回收

在这里插入图片描述
在这里插入图片描述WeakHashMap底层的entry数组,是用来弱引用,只要GC就回收

4 虚引用

在这里插入图片描述在这里插入图片描述

垃圾回收器介绍

评估GC的性能指标

1吞吐量
在这里插入图片描述
2暂停时间
在这里插入图片描述
吞吐量和暂停时间综合
在这里插入图片描述
在这里插入图片描述垃圾回收器的历史
在这里插入图片描述
7款经典的垃圾回收器
在这里插入图片描述分代搭配使用的垃圾回收器

在这里插入图片描述在这里插入图片描述在这里插入图片描述

1.serial回收器:串行回收

在这里插入图片描述 在这里插入图片描述

2-ParNew回收器-并行回收

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

3 Parallel Scavenge回收器-吞吐量优先

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

4CMS(Concurrent Mark Sweep)回收器-低延迟

在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述在这里插入图片描述参数的设置
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

5 G1回收器–区域化分代式

在这里插入图片描述在这里插入图片描述在这里插入图片描述G1回收器的优点
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述回收器的适用场景G1

在这里插入图片描述

Region化零为整

在这里插入图片描述在这里插入图片描述在这里插入图片描述G1垃圾回收的回收过程

在这里插入图片描述
在这里插入图片描述

1 youngGc的过程在这里插入图片描述

G1回收器垃圾回收过程:Remembered Set记忆集,主要是来记录下每一个region中的对象的引用,如果是本region中引用用到,就不需要记录,要是其他region中的引用用到,就要写在记忆集中,这样可以不用全局扫描就可以判断标记垃圾

在这里插入图片描述在这里插入图片描述G1工作过程

在这里插入图片描述
收流程1,先进行年轻代的GC.
在这里插入图片描述年轻代回收的过程
在这里插入图片描述2并发标记过程,针对老年代的
在这里插入图片描述3混合回收
在这里插入图片描述在这里插入图片描述在这里插入图片描述G1回收器的优化建议

在这里插入图片描述

垃圾回收器的总结

在这里插入图片描述
怎么选择合适的垃圾回收器
在这里插入图片描述
GC信息的打印
在这里插入图片描述在这里插入图片描述在这里插入图片描述

ZGC的介绍

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值