一. 类加载的流程
一般分为三步,也可以称为 5 小步,因为三大步是加载,链接,初始化,其中链接又分为了验证,准备,解析三小步
- 加载 : 将字节码文件加载到内存中
- 验证 : 检查class文件是否符合虚拟机要求,避免安全风险。
- 准备 : 分配内存给静态变量并设置初始值。
- 解析 : 将类的二进制数据中的符号引用替换为直接引用。
- 初始化 : 开始真正执行类中定义的Java程序代码
二. 类加载器
JVM提供了3种类加载器
- 启动类也叫引导类加载器Bootstrap ClassLoader(负责加载 JAVA_HOME\lib rt.jar)
- 扩展类加载器Extension ClassLoader(负责加载 JAVA_HOME\lib\ext)
- 应用程序类加载器ApplicationClassLoader(负责加载用户路径(classpath)上的类库(我们自己定义的类))
三. 双亲委派机制
- 加载一个类时,先判断此类是否已经被加载,如果类已经被加载则返回;
- 如果类没有被加载,则先委托父类加载(父类加载时会判断该类有没有被自己加载过),如果父类加载过则返回;如果没被加载过则继续向上委托;
- 如果一直委托都无法加载,子类加载器才会尝试自己加载
(或)双亲委派机制指的是:当一个类加载器接收到加载类的任务时,会自底向上查找是否加载过再由顶向下进行加载。
四. 为什么要采用双亲委派机制
1)避免核心API被篡改
2)避免类的重复加载
五. 运行时数据区
- 程序计数器:
记录当前线程所执行的字节码位置
2.虚拟机栈:
描述方法执行的内存模型,每个方法执行时会创建一个栈帧,栈帧分为局部变量表,操作数栈,动态链接,方法出口(返回地址)。
每个线程私有
3. 本地方法栈:
本地方法栈和虚拟机栈的作用非常相似,区别不过是虚拟机栈为JVM执行Java方法服务,而本地方法栈为JVM执行Native方法服务。本地方法栈也会抛出StackOverflowError
4.方法区:
存储类信息、常量、静态变量等数据。
所有线程共享
5.堆:
存放对象实例,是垃圾收集的主要区域。
所有线程共享
六. 什么是OOM
是OutOfMemoryError的缩写,意思是内存溢出错误。当我们的一个Java程序试图申请内存空间时,但是可用内存已经耗尽,无法再分配给程序足够的空间使用时,就会抛出OOM错误。
七. 了解过内存溢出和内存泄漏吗?
一般情况下是生命周期短的对象被生命周期长的对象所引用,导致生命周期短的对象一直不能被释放,这就是产生内存泄漏的原因,大量的内存泄漏就会导致内存溢出。比如一个静态的集合就容易导致内存泄漏,一般情况static的生命周期跟应用程序保持一致,然而它引用了生命周期短的对象,导致生命周期短的对象不能回收,所以我们之前在使用threadLocal存储用户信息的时候,当线程获取完用户数据之后调用remove方法移除用户信息,这样就防止了内存泄漏
八. 什么是垃圾回收(GC)
垃圾回收是一种用于释放内存中不再需要的对象所占用的空间的过程。其目的是防止内存泄漏,即释放已经死亡或长时间未使用的对象,以便有效地利用可用内存。
九. 怎么去定义垃圾
a.引用计数法:
对象头部有一个计数器,每被引用一次就加1,置为null时减1。计数器为0则对象可 回收。但此方法存在循环引用问题。
b.可达性分析法:通过GC Roots引用链确定对象是否可以回收。如果对象能追溯到GC Roots (无论直接或间接),则不可回收;否则可回收
GC Roots 包括本地变量表、静态或常量对象和Native方法。
十. 怎么回收垃圾
a.标记清除算法
找出并标记可回收对象,然后清理。有内存碎片问题。
b.复制回收算法
把内存分成两块,标记存活对象并移到另一块,然后清理原来那块。解决了内存碎片问题,但只用了一半内存,使用率低。
c.标记整理算法
标记可回收对象并移至一端,然后清理。解决了内存碎片及使用率问题,但对象地址改变,效率较低。
d.分代收集算法
大部分对象朝生夕死,在新生代Eden区分配内存。当Eden区满时,发起Minor GC,清空Eden区,将存活对象移至Survivor或Old区。
十一. Stop the World机制
这是垃圾收集过程中的一个阶段,此时所有的应用线程都被暂停,只有垃圾收集线程在工作。STW的时长直接影响系统响应速度。
十二.什么时候对象会进入老年代
a.form或to区满了
b.from和to来回迭代15次(可配置)
c.大对象直接进入老年(可配置)
十三. 你了解过哪些垃圾回收器
十四. CMS收集器与G1收集器的区别:
1、使用范围不同:CMS是老年代收集器,可以配合新生代的Serial和ParNew一起使用。而G1能处理老年代和新生代,单独使用。
2、STW时间不同:CMS目标是最小停顿,G1可以预测停顿时间。
3、垃圾碎片问题:CMS使用"标记-清除",可能造成内存碎片;G1使用"标记-整理",降低了碎片问题。
十五. jvm有没有最大内存限制
jvm的最大内存受物理服务器内存限制,一般32位操作系统大概在4G左右。64位操作系统无限制,但是一般设置为6G左右
十六.你有没有做过线上调优的工作、你有没有做过jvm调优、如果生产环境(线上)CPU加载过高你该如何排查、如果线上卡顿如何排查
在生产环境出现卡顿、CPU负载高、OOM等情况时,我们可以通过命令和工具进行分析和调优。
使用top命令查看占用CPU过高的进程,然后使用top -Hp 进程号找到占用资源过多的线程。printf 线程id将线程ID转换成十六进制格式,再使用jstack进程ID | grep 线程号来定位线程名称。如果是VM Thread,表明是GC线程卡住,可使用jstat-gc查看垃圾回收情况。
如果发现fullGC频繁,通常是因为老年代回收问题,可能是新生代过小或者幸存者区小。通过-Xms设置初始堆大小、-Xmx设置最大堆大小以及-XX:NewSize设置新生代大小来配置内存。
对于代码运行的线程,可以直接使用jstack进程ID | grep -n 16进制线程ID来定位问题所在的代码行。
当线程出现OOM时,可以使用jmap -dump(:format=b,file=myfile 进程ID)来生成堆信息快照,然后通过VisualVM进行离线分析,定位占用内存较多的对象和类,从而优化代码。