JVM
探究
面试问题:
请你谈谈你对jvm
的理解?java8虚拟机和之前的更新变化?
答:理解如该文档,java8将方法区被取代为了元空间,字符串常量数据改存到堆里面,元空间改用本地内存
什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?
答:OutOfMemoryError(内存不足错误),可能是堆内存空间不足、元空间内存不足或内存泄漏(静态集合持有对象引用,即使对象已无业务用途,仍无法被 GC 回收);
栈溢出指线程的栈深度超过虚拟机允许的最大深度,常见原因是无限递归
JVM的常用调优参数有哪些?
答:JVM 调优参数主要用于调整内存分配(大小)、垃圾回收策略(GC算法)、线程(大小)管理等核心组件的行为。
内存快照如何抓取,怎么分析Dump文件?
答:内存快照是 Java 虚拟机(JVM)在某一时刻的内存镜像,包含所有对象的状态、引用关系和类信息。常用于分析内存泄漏、大对 象占用和 GC 效率问题。抓取:自动生成(OOM时)、JDK命令抓取或IDEA插件检测工具(Profile)
谈谈jvm中对类加载器的认识?
答:将字节码文件加载到内存中,并生成Java.lang.Class对象,双亲委派机制(应用类加载器->扩展类->启动类->扩展类->应用类)...
JVM的体系结构
java栈、本地方法栈和程序计数器是不可能存在垃圾,否则程序会堵塞崩溃。所以不需要进行垃圾回收
jvm调优都是在堆和方法区(特殊的堆)里面调优,99%在调堆
方法区用于存储类的常量池,元数据和静态变量等,java8后用元空间取代的方法区,元空间使用本地内存(Native Memory)来存储类的元数据,其大小仅受系统可用内存的限制。同时,字符串常量池被移到了堆内存中。可以通过 - XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 等参数来配置元空间的大小。
类加载器
作用:负责将字节码文件(.class)从文件系统、网络或其他来源加载到内存中,并生成对应的java.lang.Class
对象。
1.虚拟机自带的加载器
2.启动类(根/bootstrap)加载器 Bootstrap ClassLoader
3.扩展类加载器(EXC) Extension ClassLoader
4.应用程序加载器 Application ClassLoader
双亲委派机制
双亲委派机制:确保类加载的安全性和一致性
1.类加载器收到类加载请求!
2.将请求向上委托给父类加载器,一直向上委托,直到启动类加载器 Application ClassLoader->Extension ClassLoader- >Bootstrap ClassLoader
3.
应用类加载器收到请求,将其委派给扩展类加载器。
扩展类加载器再委派给启动类加载器。
启动类加载器在核心类库中未找到MyClass
,返回null
。
扩展类加载器尝试加载,仍未找到,返回null
。
应用类加载器最终尝试从classpath
加载该类,成功则返回,失败则抛出ClassNotFoundException
。
4.null:表示java调用不到/不存在该加载器~ (C,C++) java=C++--
Native关键字
凡是带了native关键字的,说明java的作用范围达不到了,会去调用底层c语言的库!
会进入本地方法栈,调用本地方法接口JNI(java native interface)
JNI的作用:扩展java的使用,融合不同的编程语言为java使用。 内存区域中专门开辟了一块标记区域:Native Method Stack(本地方法栈),登记native方法,在最终执行的时候,加载本地方法库中的方法通过JNI执行
本地方法栈
本地方法栈(Native Method Stack)是 Java 虚拟机(JVM)内存结构中的一部分,用于支持本地方法(Native Method)的执行。
本地方法是由非 Java 语言(如 C、C++)实现的方法,通过 JNI(Java Native Interface)或 JNA(Java Native Access)机制在 Java 代码中调用。
PC寄存器(程序计数器)
就是程序计数器:Program Counter Register
每一个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向的一条指令地址, 也就是即将要执行的代码) 在执行引擎读取下一条指令,是一个非常小内存空间
方法区(Method Area/元空间)
方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,
简短来说,所有定义的方法的信息都存储在该区域,此区域属于共享空间
方法区用于存储类的常量池,元数据和静态变量等,java8后用元空间取代的方法区,元空间使用本地内存(Native Memory)来存储类的元数据,其大小仅受系统可用内存的限制。同时,字符串常量池被移到了堆内存中。可以通过 - XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 等参数来配置元空间的大小。
static final Class 运行时常量池
栈帧
-
位置:栈帧位于Java 虚拟机栈(JVM Stack) 中,每个线程在创建时会分配一个虚拟机栈,用于存储该线程执行的所有方法对应的栈帧。
-
生命周期:栈帧随着方法的调用而创建,方法执行结束后销毁(无论是正常返回还是抛出异常)。
-
活动栈帧:每个线程在同一时刻只有一个活动栈帧(位于栈顶),称为当前栈帧,对应的方法称为当前方法。
-
组成结构: 局部变量表(Local Variables) :存储方法参数和方法内定义的局部变量
操作数栈(Operand Stack) :方法执行过程中临时存储数据的区域,用于算术运算、方法调用参数传递等
动态连接(Dynamic Linking):将字节码中的符号引用转换为直接引用,支持方法调用的动态绑定。
每个栈帧包含一个指向运行时常量池中该方法所属类的引用。
方法调用时,通过符号引用(如
com.example.MyClass.method()
)在运行时常量池中查找并转换为直接引用 (方法的内存地址的映射关系)。 方法返回地址(Return Address):记录方法执行完毕后返回的位置
堆Heap
一个JVM只有一个堆内存,堆内存的大小是可以调节的
类加载器读取了类文件后会将说明东西放到堆中? 类,方法,变量~,保存我们所引用类型的真实对象;、
堆内存中细分区域:
-
新生区(伊甸园区) YOUNG/NEW
-
养老区 old
-
永久区 (Java8后改为了元空间(方法区))
GC垃圾回收,主要在伊甸园区和养老区
假设内存不够,OOM(OutOfMemoryError),堆内存不够!
新生区
- 作用:存储新创建的对象,大多数对象在此区域被快速回收。
- 分区
- Eden 区:对象初始分配的区域,所有对象都是在这new出。
- Survivor 区:分为两个相等大小的区域(S0 和 S1),用于存放 GC 后存活的对象。
- GC 特点:频繁执行 Minor GC,采用复制算法。
老年区
- 作用:存储长期存活的对象(如缓存对象、单例实例)。
- 对象进入条件
- 经过多次 Minor GC 后仍存活的对象(默认 15 次,可通过
-XX:MaxTenuringThreshold
配置)。 - 大对象(超过
-XX:PretenureSizeThreshold
设置的阈值)直接进入老年代。
- 经过多次 Minor GC 后仍存活的对象(默认 15 次,可通过
- GC 特点:较少执行 Full GC,采用标记 - 清除或标记 - 整理算法。
GC 触发条件
- Minor GC:Eden 区空间不足时触发。
- Full GC:老年区空间不足、元空间溢出;针对 JVM 堆内存所有区域的垃圾回收,会扫描所有存活对象,并回收不再使用的对象占用的内存。
永久区(Java8后改为了元空间(方法区))
这个区是常驻内存(计算机本地内存)。用来存放JDK自身携带的Class对象,interface元数据,存储的是java运行时的一些环境或类信息,这个区域不存在GC回收,关闭虚拟机就释放内存
OOM情况:
- 一个启动类加载了大量第三方jar包;
- Tomcat部署了太多的应用;
- 大量动态生成的反射类,不断被加载,直到内存满了
堆内存调优
调优核心目标
减少 Full GC 频率:Full GC 会导致长时间 STW(Stop The World)。
降低 Minor GC 停顿时间:频繁 Minor GC 会影响系统响应。
避免内存溢出:合理设置堆大小,防止OutOfMemoryError
。
GC(垃圾回收机制)
垃圾回收算法:
1. 标记 - 清除(Mark-Sweep)
流程:标记可达对象 → 清除未标记对象。
缺点:产生内存碎片,可能导致大对象无法分配。
2. 复制(Copying)
流程:将内存分为两块,每次只使用一块,GC 时将存活对象复制到另一块。
优点:无内存碎片,效率高。
最佳使用场景:对象存活度较低的时候;
缺点:浪费一半内存空间(适用于新生代)。
3. 标记 - 整理(Mark-Compact)
流程:标记可达对象 → 将存活对象移至一端 → 清除边界外的内存。
优点:无内存碎片(适用于老年代)。
总结:
内存效率:复制算法>标记清除>标记整理(时间复杂度)
内存整齐度:复制算法=标记整理算法>标记清除算法
内存利用率:标记整理算法=标记清除>复制
没有最好的算法,只有最合适的算法----->GC:分代收集方法
沙箱安全机制
沙箱安全机制(Sandbox Security Model)是一种隔离运行环境的安全技术,用于限制不可信代码的访问权限,防止其对系统造成破坏。在计算机领域,沙箱机制被广泛应用于操作系统、编程语言、浏览器等多个层面
沙箱的核心原理:
-
隔离执行:将不可信代码(如插件、第三方库、用户上传的程序)限制在一个独立的环境中运行,使其无法访问或修改系统资源(如文件、网络、进程)。
-
权限控制:通过细粒度的权限策略,严格限制沙箱内代码的操作范围(如只读文件访问、禁止网络连接)。
-
资源限制:限制沙箱内代码的资源消耗(如 CPU、内存、磁盘 IO),防止 DoS 攻击或资源耗尽。
三种JVM
- sun公司 HotSpot
- BEA JRockit
- IBM J9VM