JVM
2022-10-26 07:46:14 0 举报
AI智能生成
jvm之实现
作者其他创作
大纲/内容
java 如何从源代码转换成机器码执行的
内存结构
哪些是线程私有的,哪些是线程共享的
线程私有:程序计数器、虚拟机栈、本地方法栈
线程共享:堆、方法区, 堆外内存(Java7的永久代或JDK8的元空间、代码缓存)
程序计数器
虚拟机栈
栈中存储什么?
本地方法区
为什么要使用本地方法
通过本地方法,我们可以实现用 Java 与实现了 jre 的底层系统交互, JVM 的一些部分就是 C 语言写的。
有时 Java 应用需要与 Java 外面的环境交互,这就是本地方法存在的原因。
堆
在 JDK 7 版本及 JDK 7 版本之前,堆内存被通常分为下面三部分:
1. 新生代内存(Young Generation)
2. 老生代(Old Generation)
3. 永久代(Permanent Generation)
1. 新生代内存(Young Generation)
2. 老生代(Old Generation)
3. 永久代(Permanent Generation)
JDK 8 版本之后 PermGen(永久) 已被 Metaspace(元空间) 取代,元空间使用的是直接内存
Java直接内存?
Direct Memory
- 常见于 NIO 操作时,用于数据缓冲区
- 分配回收成本较高,但读写性能高
- 不受 JVM 内存回收管理
- 常见于 NIO 操作时,用于数据缓冲区
- 分配回收成本较高,但读写性能高
- 不受 JVM 内存回收管理
直接内存是操作系统和 Java 代码都可以访问的一块区域,无需将代码从系统内存复制到 Java 堆内存,从而提高了效率。
方法区
运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本/字段/方法/接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将类在加载后进入方法区的运行时常量池中存放。
堆外内存
谈谈JVM中的常量池?
字符串常量池在JVM哪个位置
String 类和常量池?
对象的访问定位的两种方式(句柄和直接指针两种方式)?
谈谈对OOM的认识?如何排查OOM的问题?
除了程序计数器,其他内存区域都有 OOM 的风险。
栈一般经常会发生 StackOverflowError,比如 32 位的 windows 系统单进程限制 2G 内存,无限创建线程就会发生栈的 OOM
栈一般经常会发生 StackOverflowError,比如 32 位的 windows 系统单进程限制 2G 内存,无限创建线程就会发生栈的 OOM
同时 jstat 查看监控 JVM 的内存和 GC 情况,先观察问题大概出在什么区域;
使用 MAT 工具载入到 dump 文件,分析大对象的占用情况,比如 HashMap 做缓存未清理,时间长了就会内存溢出,可以把改为弱引用 。
使用 MAT 工具载入到 dump 文件,分析大对象的占用情况,比如 HashMap 做缓存未清理,时间长了就会内存溢出,可以把改为弱引用 。
JVM8 为什么要增加元空间,带来什么好处
类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。
永久代会为 GC 带来不必要的复杂度,并且回收效率偏低
表面上看是为了避免OOM异常。因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限,
但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。
当使用元空间时,可以加载多少类的元数据就不再由MaxPermSize控制, 而由系统的实际可用空间来控制。
但是不是总能知道应该设置为多大合适, 如果使用默认值很容易遇到OOM错误。
当使用元空间时,可以加载多少类的元数据就不再由MaxPermSize控制, 而由系统的实际可用空间来控制。
元空间的特点:
每个加载器有专门的存储空间。
不会单独回收某个类。
元空间里的对象的位置是固定的。
如果发现某个加载器不再存货了,会把相关的空间整个回收
每个加载器有专门的存储空间。
不会单独回收某个类。
元空间里的对象的位置是固定的。
如果发现某个加载器不再存货了,会把相关的空间整个回收
垃圾回收算法
对象创建和内存分配策略
为什么要有survivor区
为什么要有两个survivor
动态对象年龄的判断
HotSpot VM里GC的种类
如何判断一个对象是否存活?
垃圾标记
强引用、软引用、弱引用、虚引用
被引用的对象就一定能存活吗?
GC root有哪些 ?
实例变量可以是GC root 吗 ?
如何判断一个类是无用的类
空间分配担保原则?
如何判断一个常量是废弃常量
垃圾回收算法
标记-清除算法
将垃圾标记,然后清除,不需要移动对象,但产生内存碎片
标记-整理算法
将不被GC Root引用的对象回收,清除其占用的内存空间。然后整理剩余的对象,可以有效避免因内存碎片而导致的问题
复制算法
先将被GC Root引用的对象从FROM放入TO中,再回收不被GC Root引用的对象。
然后交换FROM和TO。这样也可以避免内存碎片的问题,但是会占用双倍的内存空间。
然后交换FROM和TO。这样也可以避免内存碎片的问题,但是会占用双倍的内存空间。
对比
分代垃圾回收
不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率
年轻代,区域相对老年代较小,对象生命周期短、存活率低,回收频繁
老年代,对象生命周期长,存活率高,回收不频繁
分代垃圾回收流程
① 新创建的对象都被放在 新生代的伊甸园 中
② 当伊甸园空间不足时,会采用 复制算法 进行垃圾回收,这时的回收叫做 ==Minor GC== ;把 伊甸园和幸存区From 存活的对象先复制到幸存区To中,此时 存活的对象寿命+1 ,并清理掉未存活的对象,最后再交换幸存区From和幸存区To;
③ 再次创建对象,若新生代的伊甸园又满了,则同上;
④ 如果经历多次垃圾回收,某一对象均未被回收,寿命不断+1,当寿命达到阈值时(最大为15,4bit,在对象头 1<<4,可动态调节)就会被放入老年代中;
⑤ 如果老年代中的内存都满了,就会先触发Minor GC 如果内存还是不足,则会触发 Full GC ,扫描 新生代和老年代中 所有不再使用的对象并回收、
大对象处理策略
当遇到一个 较大的对象 时,就算新生代的 伊甸园 为空,也 无法容纳该对象 时,会将该对象 直接晋升为老年代
某个线程的内存溢出了而抛异常(out of memory),会不会让其他的线程结束运行?
当一个线程**抛出OOM异常后**,**它所占据的内存资源会全部被释放掉**,从而不会影响其他线程的运行,**进程依然正常进行**
GC
JVM中一次完整的GC是什么样子的?
Minor Gc 和 Full GC 有什么不同呢?
触发新生代GC,如果存活对象总量大于survivor区容量,咋办 ?
GC Cause、日志分析
垃圾回收器
相关概念
并行收集:指多条垃圾收集线程并行工作,但此时用户线程仍处于等待状态。
并发收集:指用户线程与垃圾收集线程同时工作(不一定是并行的可能会交替执行)。用户程序在继续运行,而垃圾收集程序运行在另一个 CPU 上
吞吐量:即 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值(吞吐量 = 运行用户代码时间 / ( 运行用户代码时间 + 垃圾收集时间 )),也就是。例如:虚拟机共运行 100 分钟,垃圾收集器花掉 1 分钟,那么吞吐量就是 99% 。
垃圾回收器种类
串行回收器。Serial、Serial old
并行回收器。ParNew、Parallel Scavenge、Parallel old
并发回收器。CMS、G1
G1
G1什么时候会stop the world
Young Collection:对新生代垃圾收集,产生stw
Mixed Collection:混合收集中,最终标记会stw,拷贝存活会stw
垃圾回收阶段
Young Collection:对新生代垃圾收集
Young Collection + Concurrent Mark:如果老年代内存到达一定的阈值了,新生代垃圾收集同时会执行一些并发的标记。
Mixed Collection:会对新生代 + 老年代 + 幸存区等进行混合收集,然后收集结束,会重新进入新生代收集。
CMS(Concurrent Mark Sweep)
一种以获取最短回收停顿时间为目标的老年代收集器
详细说一下CMS的回收过程?CMS的问题是什么?
主要优点:并发收集、低停顿。但是它有下面三个明显的缺点:
1、对 CPU 资源敏感;
2、无法处理浮动垃圾;
3、它使用的回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生。
1、对 CPU 资源敏感;
2、无法处理浮动垃圾;
3、它使用的回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生。
有哪几种垃圾回收器,各自的优缺点是什么?
类加载
什么是类加载?
类加载的过程?
加载 -- 连接(验证、准备、解析)---
一个class 文件,平时被存在磁盘上,这些内容被load到内存,发生了什么?
内存中实际上创建了两块内容
1 一块内容就是二进制的文件被加载到内存中
2 与此同时,生成了 class 类的对象,单例,帮我们解析好,这个对象指向了这块内容,
以后就是通过我们自己写的对象访问这个class类的对象,再访问到我们内存的class文件
class的对象,在方法区,我们自己写的实例化对象,在堆中
1 一块内容就是二进制的文件被加载到内存中
2 与此同时,生成了 class 类的对象,单例,帮我们解析好,这个对象指向了这块内容,
以后就是通过我们自己写的对象访问这个class类的对象,再访问到我们内存的class文件
class的对象,在方法区,我们自己写的实例化对象,在堆中
什么是类加载器,常见的类加载器有哪些?
Bootstrap ClassLoader(启动类加载器)
Extension ClassLoader(拓展类加载器)
Application ClassLoader(应用程序类加载器)
自定义类加载器
类加载器比较
什么是双亲委派模型?
双亲委派过程?
为什么需要双亲委派模型?
那怎么打破双亲委派模型?
逃逸分析
tomcat
分支主题
自定义类加载器
实战
类加载
什么场景下需要自定类加载器
如何自定义类加载器
垃圾回收
垃圾回收器选型
Full GC
系统频繁Full GC导致系统卡顿是怎么回事
对于Full GC次数过多,主要有以下两种原因:
代码中一次获取了大量的对象,导致内存溢出,此时可以通过eclipse的mat工具查看内存中有哪些对象比较多;
内存占用不高,但是Full GC次数还是比较多,此时可能是显示的System.gc()调用导致GC次数过多,这可以通过添加-XX:+DisableExplicitGC来禁用JVM对显示GC的响应。
代码中一次获取了大量的对象,导致内存溢出,此时可以通过eclipse的mat工具查看内存中有哪些对象比较多;
内存占用不高,但是Full GC次数还是比较多,此时可能是显示的System.gc()调用导致GC次数过多,这可以通过添加-XX:+DisableExplicitGC来禁用JVM对显示GC的响应。
频繁GC问题怎么排查
案例
内存泄漏
哪些地方会出现OOM
死锁问题
CPU或者内存使用率过高怎么办?
JVM运行情况预估
分支主题
常用工具
Jps
查看其进程id
JMAP
查看内存信息,实例个数以及占用内存大小
查看某个进程的堆信息
jmap -heap pid
堆内存快照
jmap‐dump:format=b,file=eureka.hprof14660
jvisualvm
导入dump文件进行分析
jstack
查看线程情况
jstack 线程id
Jinfo
查看正在运行的Java应用程序的扩展参数
jinfo -sysprops pid
Jstat
查看堆内存各部分的使用量,以及加载类的数量
垃圾回收统计
jstat -gc pid
分支主题
堆内存统计
jstat -gacapactity pid
新生代回收
jstat -gcnew pid
其他
Arthas
dashboard
查看整个进程的运行情况,线程、内存、GC、运行环境信息
输入thread可以查看线程详细情况
输入 thread加上线程ID 可以查看线程堆栈
输入 thread -b 可以查看线程死锁
0 条评论
下一页