初探JVM
JVM探究
- 请你谈谈你对JVM的理解?java8虚拟机和之前的变化与更新
- 什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?
- JVM的常用调优参数有哪些
- 内存快照如何抓取,怎么分析Dump文件?可以利用jprofiler这个插件
- 谈谈JVM中,类加载器你的认识
1、JVM的位置
2、JVM的体系结构
3、类加载器
4、双亲委派机制
首先你要了解JVM中提供了三层ClassLoader
- BootstrapClassLoader:主要负责加载和心类库(例如:java.lang.等)
- ExtClassLoader:主要是负责加载jre/lib/ext目录下的一些扩展jar
- APPClassLoader:主要是负责加载应用程序的主函数类
概念:当一个类收到类加载请求,它首先不会尝试自己去加载,而是把这个请求委派给父类完成,每一层次类加载器都是如此,一次所有的加载请求都应该传送到启动类加载中,只有当父类加载器反馈自己无法完成这个请求的时候,子类加载器才会自己尝试加载
优势:这样可以防止核心库别随意篡改;避免重复加载。
5、沙箱安全机制、Native、PC寄存器、方法区、栈、三种JVM
5、方法区与元空间的解释与区别
11、堆,新生去、老年区、永久区,堆内调优
6、GC
1、常用算法:标记清除法、标记压缩、复制算法、引用计数器
6.1、复制算法:
-
好处:没有内存碎片
-
坏处:浪费了内存空间;多了一般空间永远是空的To,假设对象100%存活(极端情况)
复制算法最佳使用场景:对象存活度比较低:新生区~
6.2、标记压缩:
对标记清除法的优化
-
优点:不需要额外的内存空间
-
缺点:两次扫描和一次压缩,比较耗时
-
解决了:标记清除法的内存碎片化
6.3、总结
- 内存效率:复制算法 > 标记清除算法 > 标记压缩算法(时间复杂度)
- 内存整齐度:复制算法 = 标记压缩算法 > 标记清除算法
- 内存利用率:标记压缩算法 = 标记清除算法 > 复制算法
没有最优的算法只有最合适的算法------->GC分代收集算法
年轻代
- 存活率低
- 复制算法
老年代:
- 区域大:存活率
- 标记清除(内存碎片不太多)+标记压缩混合实现
7、JMM
1、什么是JMM?
JMM是 Java Memory Model
2、它是干啥的?
作用:缓存一致协议,用于定义数据读写的规则
JMM定义了线程工作内存之间的抽象关系:线程之间的共享变量存储在主内存中,每一个线程都有一个私有的本地内存。
解决共享对象可见性这个问题:可以用 volatile 关键字和synchronized同步机制
8代码和IDEA虚拟机参数配置
8.1、这是IDEA的java虚拟机参数配置的地方
8.2、代码
package 寒假训练.狂神.JVm;
public class Demon2 {
public static void main(String[] args) {
//返回虚拟机试图使用的最大内存
long max = Runtime.getRuntime().maxMemory();
//返回jvm的初始化的总内存
long total = Runtime.getRuntime().totalMemory();
System.out.println("max="+max+"字节\t"+(max/(double)1024/1024)+"MB");
System.out.println("total="+total+"字节\t"+(total/(double)1024/1024)+"MB");
//默认情况下:分配的总内存 是电脑内存的1/4,而初始化的内存:1/64
//OOM:内存溢出
/**
* 解决方法:1、尝试扩大堆的内存空间,其实就是调JVM的参数。
* 格式:-Xms1024m -Xmx1024m -XX:+PrintGCDetails
*两个1024可以替换成自己想要替换的数字
* 2、分析内存,看一下哪个地方出现了问题(专业工具jprofiler)
*/
}
}
OOM的代码
package 寒假训练.狂神.JVm;
import java.util.ArrayList;
//-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
public class Demon3 {
public static void main(String[] args) {
byte[] array = new byte[1*1024*1024];
ArrayList<Demon3> list = new ArrayList<>();
int count = 0;
try {
while (true){
list.add(new Demon3());
count=count+1;
}
} catch (Error error){
System.out.println(error.getMessage());
}
}
}