jdk-jre-jvm 区别
jdk包含jre,jre包含jvm
Jdk是一个合集,包含一些编译工具
Jre是(class)Java运行环境,包含一些插件,包含jvm
Jvm 是最基础的,做翻译的,class翻译成操作系统上的指令(0101)
运行时数据区
线程私有:程序计数器、虚拟机栈、本地方法栈
线程共享:堆、方法区
程序计数器(唯一不会OOM的区域):记录指向当前线程正在执行的字节码指令的地址(行号)。
Java是多线程的,意味着线程切换,确保多线程情况下的程序正常执行
栈(stack):数据结构
为什么jvm要使用栈?答:更好的兼容方法调用方法的特点。
虚拟机栈(大小设置-Xss 1M,虚拟机栈就是在栈数据结构上的一个种拓展):存储当前线程运行方法所需的数据,指令、返回地址
栈帧:多个方法,每个方法就是一个栈帧
栈帧是方法转换为字节码,在虚拟机中运行过程
栈默认大小为1M,StackOverFlowError(栈溢出)的出现是因为方法死递归调用本方法。OOM栈内存溢出,很多线程在跑,10万个线程栈空间就是10万*1M
本地方法栈:是保存的native方法信息,jvm调用后,jvm不为其在虚拟机中创建栈帧,jvm只是简单动态并直接调用native方法。
方法区(永久代1.7及以前,元空间1.8):存放类信息、常量(final)、静态变量(static),即时编译的代码(js)
永久代参数:-XX:PermSize;-XX:MaxPermSize
元空间参数:-XX:MetaspaceSize; -XX:MaxMetaspaceSize;
堆(-Xms;-Xmx;-Xmn):关注内存的分配(new关键字,反射等)与回收(回收算法,收集器等)。变量(int)实例变量,没有final、static修饰的变量。几乎所有对象都在堆中分配
-Xms: 堆的最小值
-Xmx: 堆的最大值
-Xmn: 新生代大小
-XX:NewSize 新生代最小值
-XX:MaxNewSize: 新生代最大值
基本数据类型是放在栈中还是放在堆中? 这取决于基本类型声明的位置。
- 在方法中声明的变量,即该变量是局部变量,每当程序调用方法时,系统都会为该方法建立一个方法栈,其所在方法中声明的变量就放在方法栈中,当方法结束系统会释放方法栈,其对应在该方法中声明的变量随着栈的销毁而结束,这就局部变量只能在方法中有效的原因
- 在类中声明的变量是成员变量,也叫全局变量,放在堆中的(因为全局变量不会随着某个方法执行结束而销毁)
运行时常量池:字符引用、字面量(String a = “123”, 123为字面量)
字符串常量池在堆, 运行时常量池方法区
元空间和永久代的区别?元空间只受限于机器内存,可以无限扩容。永久代受制于堆。
直接内存:jvm直接管理不了的,不属于虚拟机。NIO使用本地内存
jvm内存参数设置
参考值:
java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar api.jar
关于元空间的JVM参数有两个:-XX:MetaspaceSize=N和 -XX:MaxMetaspaceSize=N
- -XX:MaxMetaspaceSize: 设置元空间最大值, 默认是-1, 即不限制, 或者说只受限于本地内存大小。
- -XX:MetaspaceSize: 指定元空间触发Fullgc的初始阈值(元空间无固定初始大小), 以字节为单位,默认是21M,达到该值就会触发 full gc进行类型卸载, 同时收集器会对该值进行调整: 如果释放了大量的空间, 就适当降低该值; 如果释放了很少的空间, 那么在不超 过 -XX:MaxMetaspaceSize (如果设置了的话) 的情况下, 适当提高该值。这个跟早期jdk版本的 -XX:PermSize 参数意思不一样,- XX:PermSize 代表永久代的初始容量。
- 由于调整元空间的大小需要Full GC,这是非常昂贵的操作,如果应用在启动的时候发生大量Full GC,通常都是由于永久代或元空间发生 了大小调整,基于这种情况,一般建议在JVM参数中将MetaspaceSize和MaxMetaspaceSize设置成一样的值,并设置得比初始值要大, 对于8G物理内存的机器来说,一般我会将这两个值都设置为256M。