JVM常见知识点总结

JVM常见知识点总结

1、JVM的位置
可以把JVM理解为一个应用程序,它是运行在操作系统之上的,我们在安装java运行环境JRE的时候,里面就已经包含了JVM。

2、JVM的体系结构
在这里插入图片描述
栈内存中不存在GC(因为栈就是方法不断的压栈、出栈,如果有垃圾会发生堵塞,不可能有垃圾的),所以常说的JVM调优指的是操作堆内存

3、类加载器
应用程序加载器、扩展类加载器、根加载器(启动类加载器)
4、双亲委派机制
当我们创建类,并且执行方法时。会先去根加载器下面找有没有这个类,如果有,就执行根加载器下的类和方法,而不会再执行本地创建的。当根加载器下没有时,会去扩展加载器下找有没有这个类,如果有,就执行扩展加载器下的类和方法,而不会再执行本地创建的。如果没有,才会执行本地应用程序加载器。
(1)、类加载器收到类加载的请求
(2)、将该请求向上委托给父类的加载器去完成,一直向上委托,直到根加载器
(3)、根加载器检查能否加载该类,能加载就结束了,使用当前的根加载器去加载即可。如果不能,抛出异常,通知子加载器进行加载(扩展、应用)
(4)、重复3过程

5、Native
凡是带了native关键字的,说明java的作用范围达不到了,会去调用底层C语言的库。native标记的方法会进入本地方法栈,然后通过本地方法库去调用本地方法接口(JIN), 这样可以扩展java的使用,融合不同的语言为java所用(本地方法库和本地方法接口的作用就是可以调用访问底层的C、C++所写的库)。

6、PC寄存器(程序计数器)
每个线程都有一个程序计数器,是线程私有的,执行下一条指令时候加1,可以保证线程能够有序不乱的运行(有1,2,3,4,5,6,7,8这些顺序编号)

7、方法区
方法区线程共享,里面存放 静态变量、常量、代码片段(.class字节码文件)、运行时的常量池。JDK1.8之前,方法区有自己单独的空间,JDK8之后,方法区存在于堆内存的元空间(永久区)中,也就是,方法区属于堆了

8、栈
(1)一个线程一个栈,线程结束,栈内存释放
(2)不存在垃圾回收问题
(3)存放 局部变量(8种基本数据类型)、方法、对象的引用

9、三种JVM
HotSpot(我们只用这个)、JRockit、J9VM

10、堆
(1)一个JVM只有一个堆内存,所以它里面会有很多垃圾。堆内存大小可以调节
(2)堆中主要存放 实例变量、对象
(3)堆主要包括,新生区、老年区、永久区(元空间)。GC垃圾回收机制主要存在于新生区中的伊甸园区和老年区
(4)OOM(OutOfMemoryError):堆内存溢出,堆内存满了会报此错
在这里插入图片描述

11、新生区、老年区
新生区:创建对象时(new Student())就是在新生区里的伊甸园区创建的。它是类诞生和死亡的地方。大部分对象是临时对象,会在伊甸园
区用完以后直接被轻GC杀死,少部分会跑到幸存区(from、to),
极少会进入到老年区

12、永久区(元空间)
永久区常驻于内存,用来存储JDK自身携带的Class对象,也就是java运行时的一些环境,不存在垃圾回收。一般永久区是不会出现OOM的,除非几个特殊情况:一个启动类加载了大量的第三方jar包、Tomcat部署了太多的应用。
元空间逻辑上存在,物理上不存在
在这里插入图片描述

14、遇到OOM怎么办:
(1)OOM原因:新生区创建对象,存在于伊甸园区,不断的创建,不断的用轻GC回收,如果对象不多,轻GC完全可以应付在伊甸园区就把垃圾清理完毕。但是如果对象过多,产生的垃圾过多,就会跑到幸存区,这时候轻GC还在努力地做清理工作,如果垃圾还是在不断的产生,过多,那么就会跑到老年区,这时候,重GC就会登场,重GC的清理范围会比轻GC大得多,它会清理新生区、老年区里的所有垃圾。当垃圾过多,老年区也存满了,重GC也顶不住的时候,就会报OOM堆内存溢出的错误。
2、解决方法(堆内存调优):

(1)尝试扩大堆内存空间,观察运行结果,如果正常了,说明是
堆内存空间不足导致的
-Xms1024m -Xmx1024m -XX:+PrintGCDetails(打印GC信息)
-Xms:设置初始化内存分配大小
-Xmx:设置最大内存

(2)分析内存,看一下哪个地方出现了问题(专业工具Jprofiler)
在IDEA中安装Jprofiler插件,当报出OOM错误时,在IDEA
中设置Dump文件:
Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError,此时就会Dump出一个文件,然后用Jprofiler就可以打开这个文件,通过文件里面的信息就可以准确判断出程序是在哪里甚至哪几行出现了问题,然后就可以去修改。

15、GC(常用算法)
a)标记清除法

在这里插入图片描述

优点:不需要额外的内存空间
缺点:两次扫描,严重浪费时间,会产生内存碎片

b)标记压缩法
对标记清除算法进行再次优化,再次扫描,向一端移动存活的对象

在这里插入图片描述

c)复制算法:新生区主要使用复制算法。当伊甸园区满了,垃圾会进入幸存区(from、to),遵循谁空谁是to的原则,在from和to之间不断的进行交换操作。假如from、to都有数据,那么此时就需要把其中一个区的数据复制到另一个区,然后就腾出来一个空的区作为to区以方便后续的存放垃圾,这就是复制算法。每一次GC过后,伊甸园区和to区都是空的。当15次GC还没有回收掉的垃圾(默认15次,可以修改),就会进入到老年区。

优点:没有内存碎片
缺点:浪费了一半内存空间(to区永远是空的)。当垃圾过多时,从from
区复制到to区的成本太高。所以复制算法最佳使用场景:对象存活
度较低的时候,也就是在新生区使用。

d) 引用计数法(对每个对象的引用次数进行计数,次数为0的就回收。这种方法很少用,因为对象太多了,每个都计数太浪费空间了)

e)总结各个算法

		         内存效率:复制算法>标记清除>标记压缩(次数最多)
		         内存利用率:标记压缩>标记清除>复制算法(一半空间为空)
		没有最好的算法,只有更合适的算法。所以GC算法也被称为分代收集算法。

在新生区一般使用复制算法,在老年区一般使用标记清除+标记压缩(具体的清除多少轮再进行压缩是个关键,当内存碎片不多时候可以继续再进行清除,当碎片很多了再进行压缩,这也是JVM调优的关键步骤)混合实现。

<think>嗯,用户要我详细总结JVM相关的知识点,看来是遇到了面试准备或者深度学习的场景。作为Java核心,JVM确实是必须要掌握的。好的,准备详细阐述JVM的组成结构、核心机制和调优要点。需要覆盖五个核心模块:内存模型(重点堆)、加载机制、垃圾回收(重要参数)、执行引擎、工具链。准备在堆内存部分详细展开GC算法和分代概念,这是面试高频点。考虑到用户可能需要实践指导,准备补充VisualVM和Arthas的实际使用建议。最后要留四个进阶问题引导深度思考,特别是Metaspace和G1回收器这类热点。过得控制篇幅,核心概念解释要精准,比如在解释帧时准备附带局部变量表的字节码示例,这样更直观。安全点的概念可以放在执行引擎里简单提及。感觉需要强调下实际调优中的误区,比如很多人容易忽略的堆外内存问题。最后的相关问题准备设计成阶梯式的,从内存管理到新版本特性都有覆盖,这样能帮助用户系统梳理知识脉络。</think> 以下是JVM核心知识点的详细总结及解释: --- ### **一、JVM核心结构** 1. **类加载器(ClassLoader)** - **过程**:加载 → 链接(验证→准备→解析)→ 初始化 - **双亲委派机制**:子加载器委托父加载器加载,避免重复加载(`Bootstrap→Extension→Application→Custom`) - **破坏场景**:SPI(如JDBC使用线程上下文加载器) 2. **运行时数据区(Runtime Data Areas)** ```java public class JVMMemoryModel { private static final int CONST = 1; // 方法区(元空间) private int instanceVar = 2; // 堆 public void method() { int localVar = 3; // 虚拟机帧 Object obj = new Object(); // 对象在堆,引用在 } } ``` - **堆**:所有对象实例(GC主区域),分代模型:**新生代(Eden+S0+S1) + 老年代** - **方法区**:存储类信息、常量、静态变量(JDK8后由**Metaspace**替代永久代) - **虚拟机**:线程私有,存储**帧**(局部变量表、操作数、动态链接、方法出口) - **本地方法**:Native方法调用 - **程序计数器**:当前线程执行的字节码行号指示器 --- ### **二、垃圾回收(GC)** 1. **回收算法** | 算法 | 原理 | 场景 | |---|---|--| | 标记清除 | 标记→清除碎片 | 老年代CMS | | 复制 | Eden→Survivor复制 | 新生代(默认比例 8:1:1) | | 标记整理 | 标记→移动整理 | 老年代Serial/CMS后备方案 | 2. **GC分类** - **Minor GC**:清理新生代(频繁、停顿短) - **Full GC**:清理整个堆(停顿长,触发条件:老年代满、MetaSpace足、System.gc()等) 3. **常用收集器** - **Serial**:单线程新生代复制算法 - **ParNew**:多线程版Serial - **CMS**:标记清除,追求低停顿(4阶段:初始标记→并发标记→重新标记→并发清除) - **G1**:分Region收集,预测停顿时间(JDK9默认) - **ZGC**:<10ms停顿(JDK15生产可用) --- ### **三、执行引擎** 1. **解释执行**:逐行翻译字节码 2. **即时编译(JIT)** - **C1编译器**:简单优化,快速编译(Client模式) - **C2编译器**:激进优化(Server模式,内联/逃逸分析等) - **分层编译**:JDK7后默认(0解释→1C1→2C2) 3. **逃逸分析示例** ```java // JIT优化:对象未逃逸时可上分配 public void escapeTest() { Object localObj = new Object(); // 可能被优化为上分配 } ``` --- ### **四、性能监控工具** | 工具 | 用途 | |---|---| | jps | 查看Java进程 | | jstat | 监控GC统计(`jstat -gcutil [pid]`) | | jmap | 堆转储(`jmap -dump:format=b,file=heap.bin [pid]`) | | VisualVM | 图形化分析内存/线程/GC | | Arthas | 线上诊断(热更新/方法调用追踪) | --- ### **五、调优实践** 1. **参数示例** ```bash -Xms4g -Xmx4g # 堆大小(避免动态扩容) -XX:MaxMetaspaceSize=256m # 元空间上限 -XX:+UseG1GC # 使用G1收集器 -XX:MaxGCPauseMillis=200 # 目标停顿时间 ``` 2. **常见问题方向** - **频繁Full GC**:检查内存泄露(jmap + MAT分析) - **高CPU占用**:jstack查线程阻塞(死锁/循环等待) - **Metaspace溢出**:检查动态代理生成类(如CGLIB) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值