以下是我JVM学习的笔记,适合用于基本了解JVM
请你谈谈你对JVM的理解?
java8虚拟机和之前的变化更新
什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?
JVM的常用调优参数有哪些?
内存快照如何抓取,怎么分析Dump文件?知道吗
谈谈JVM中,类加载器你的认识?
1、JVM的位置 2、JVM的体系结构
3、类加载器
作用:加载class
- 虚拟机自带加载器
- 启动类(根)加载器 BOOT
- 扩展类加载器 EXC
- 应用程序加载器 APP
4、双亲委派机制:为了安全 APP --> EXC --->BOOT
1、防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
2、保证核心.class不能被篡改。不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。
5、沙箱安全机制
6、Native
1、native:用native关键字。说明java的作用范围打不到了,回去调 用底层C语言库。
2、JNI的作用:扩展java的使用,融合不同的编程语言为java所用: 最初C,C++。java诞生时c、c++横行,要立足就要调用c、c++
3、JNI在内存区域中专门开辟了一块标记区域:本地方法栈 Native Method Stack,登记了native方法。
4、执行的时候native方法会从本地方法栈,调用本地方法接口 (JNI java native interface)通过JNI 加载本地方法库中的方法。
5、在企业级应用中较为少见,通过java驱动打印机、robot等情况下 使用,掌握即可。
7、PC寄存器
程序计数器:Program Counter Register
每个线程都有一个程序计数器,是线程私有的,储存即将执行的 指令代码的地址,占用内存空间非常小,(用来计数使线程有序等, 比如线程1 线程2 线程...)
8、方法区(共享区间)
1、静态变量、常量、类信息(构造方法、接口定义)、运行时常量池 都 存在方法区中
2、实例化时 实例和实例变量赋值存在堆内存中
3、栈中存放实例的引用,方法执行时入栈,方法执行完弹栈
4、方法区和堆 有垃圾回收,栈中没有
9、栈
队列:管形、先进先出(FIFO first input first output)
栈:存放8大基本类型,对象的引用,实例的方法
桶形:先进后出
main()方法先执行,最后执行结束
栈内存 主管程序运行,生命周期和线程同步
线程结束,栈内存也就是释放了。栈不存在垃圾回收
栈帧:栈顶、栈底(程序正在执行的方法一定在栈的顶部)
每个栈帧中有:方法的索引、入参出参、本地变量、Class File、父帧、子帧
10、对象的初始化
父类的静态代码块
->子类的静态代码块
->初始化父类的属性值/父类的普通代码块(自上而下的顺序排列)
->父类的构造方法
->初始化子类的属性值/子类的普通代码块(自上而下的顺序排列)
->子类的构造方法。
注:构造函数最后执行。
11、三种JVM
Sun公司 HotSpot(一般用)
BEA公司JRockit
IBM公司J9 VM
12、堆 Heap
一个JVM只有一个堆内存,堆内存的大小是可以调节的。
类加载器读取了类文件后,一般把什么放入堆中?类、方法、常量、变量、所有引用类型的真实对象
13、新生区(Eden Space) 轻量级GC(轻GC)
新生区:伊甸园区、幸存区012345...
N次(定义上限)垃圾回收之后,进入养老区
14、老年区:重量级GC(Full GC)
GC,主要在伊甸园区和养老区。
内存满了,报OutOfMemory堆内存错误。
99%的对象都是临时对象,进不到养老区。
15永久区(JDK8之后叫 元空间)
不存在GC,关闭VM虚拟机就会释放这个区域的内存。
这个区域是常驻内存的。用来存放JDK自身携带的Class对象。Interface元数据,存的是java运行时的一些环境或类信息。
一个启动类加载了大量的第三方jar包、Tomcat部署了太多应用大量动态生成反射类。不断加载直到内存满了,就会报OOM。
Jdk6前:永久代,常量池在方法区中
Jdk7:永久代,常量池在堆中
Jdk8后:无永久代,常量池在元空间
1.8时的堆:方法区中包含一小块常量池
元空间:逻辑上存在,物理上不存在
16堆内存调优
1、OOM的处理 :设置内存 -Xms4096m -Xmx256m -XX:+PrintGCDetails
1、尝试扩大堆内存,看结果
2、分析内存,看一下哪个地方除了问题(用专业工具)
2、在项目中突然出现OOM故障,如何排除:
1、Dubug一行行分析:不现实
2、通过插件直接看到第几行出错:内存快照分析工具:MAT、Jprofiler
3、MAT,Jprofiler的作用:
1、分析Dump内存文件,快读定位内存泄漏
2、获得堆中的数据
3、获得大的对象
等等
//设置内存 -Xms4096m -Xmx256m -XX:+PrintGCDetails (打印GC信息到控制窗口)
//堆Dump -Xms4096m -Xmx256m -XX:+HeapDumpOnOutOfMemoryError (on后面是条件)
17、GC常用算法:标记清除法、标记压缩、复制算法、引用计数器法
1、引用计数法:一般不用引用计数法,给每个对象分派程序计数器,计数为0的回收
2、复制算法:每次GC,都会将Eden区中活着的对象移到幸存区中幸存区,幸存区放不下就放到养老区了。Eden区被GC后就是空的。幸存区谁空谁是to,非空from
复制算法的缺点:浪费一半空间(to得是空的),从from幸存区复制到to幸存区,如果对象 都存活,太浪费资源。因此当对象存活率低才会用复制算法
3、标记清除:回收时对活着得对象扫描进行标记,对没标记得对象扫描进行清除
缺点:两次扫描,严重浪费时间,会产生内存碎片
优点:对比复制算法 不需要额外的内存空间(空的To幸存区)
4、标记压缩:在标记清除得基础上,再次扫描,向一端移动存活得对象,防止内存碎片产生。又多了一个移动的成本
5、最好进行多次标记清除,然后进行一次标记压缩,降低成本
17、总结
内存效率(时间复杂度):复制算法 > 标记清除算法 > 标记压缩算法
内存整齐度:复制算法 = 标记压缩 > 标记清除算法
内存利用率:标记压缩算法 = 标记清除算法 > 复制算法
GC是分代收集算法:
年轻代:存活率低 用 复制算法
老年代:区域大,存活率高 用 标记清除+压缩混合
JVM学会之后想深入研究可看《深入学习JVM》
也可研究新的模型:JMM
Java Memory Model
什么是JMM ? 百度百科
干嘛的? 官方、博客、对应视频
如何学习?看 + 面试题