JAVA虚拟机
1.JVM体系结构
类装载器(ClassLoader):用来装载.class文件
运行时数据区:方法区(静态区),堆,栈,pc寄存器,本地方法栈
执行引擎:执行字节码或者本地方法
2.JVM运行的数据区
2.1栈(stack)
存储内容
存储局部变量和尚未处理好的结果(例如异常)主要是方法的调用,实例化后的引用(不是实例化对象)
注释:栈里还有栈帧喜欢研究的再去深究
2.2堆(heap)
被所有线程共享的一块内存区域,在虚拟机启动时创建,用来存储对象实例。
可以通过-Xmx和-Xms来控制堆的大小
OutMemoryError异常:当前堆中没有内存完成实例分配且堆无法再扩展。
Java堆是垃圾回收器管理的主要区域。
java堆可分为:新生代(young)和老年代(Tenured)。
持久代(Permanent)在方法区不属于heap。(JDK8废弃)
新生代:新建的对象都由新生代分配内存。
新生代由分为:Eden区和Survivor区。Eden空间不足时会把激活的对象转移到Survivor。
老年代:存放经过多次垃圾回收任然存活的对象。
2.3方法区
2.3.1持久代JDK8弃用更名为元空间
由于永久代内存经常不够用或发生内存泄露,爆出异常java.lang.OutOfMemoryError: PermGen
元空间与持久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。
2.3.2存储内容
被所有线程共享存储主要存储的是类的信息,常量池,方法数据,方法代码
2.3.3常用配置参数
1.MetaspaceSize
初始化的Metaspace大小,控制元空间发生GC的阈值。GC后,动态增加或降低MetaspaceSize。在默认情况下,这个值大小根据不同的平台在12M到20M浮动。使用Java -XX:+PrintFlagsInitial命令查看本机的初始化参数
2.MaxMetaspaceSize
限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存,影响到其他程序。在本机上该参数的默认值为4294967295B(大约4096MB)。
3.MinMetaspaceFreeRatio
当进行过Metaspace GC之后,会计算当前Metaspace的空闲空间比,如果空闲比小于这个参数(即实际非空闲占比过大,内存不够用),那么虚拟机将增长Metaspace的大小。默认值为40,也就是40%。设置该参数可以控制Metaspace的增长的速度,太小的值会导致Metaspace增长的缓慢,Metaspace的使用逐渐趋于饱和,可能会影响之后类的加载。而太大的值会导致Metaspace增长的过快,浪费内存。
4.MaxMetasaceFreeRatio
当进行过Metaspace GC之后,会计算当前Metaspace的空闲空间比,如果空闲比大于这个参数,那么虚拟机会释放Metaspace的部分空间。默认值为70,也就是70%。
5.MaxMetaspaceExpansion
Metaspace增长时的最大幅度。在本机上该参数的默认值为5452592B(大约为5MB)。
6.MinMetaspaceExpansion
Metaspace增长时的最小幅度。在本机上该参数的默认值为340784B(大约330KB为)。
2.4常量池
用final修饰的就存储在常量池 ,常量池属于方法区。
2.4.1好处
为了避免频繁的创建和销毁对象影响性能。实现了对象共享。
节省空间:常量池会将相同的字符串进行合并,只占用一个空间。
2.4.2int和integer
Integer是int封装类Integer类也是用final修饰存储在常量池,减少存储空间有就引用,没有就创建。
2.5Pc寄存器
Java虚拟机支持多线程同时执行,每条线程启动时都会创建一个pc寄存器:保存下一条将要执行指令的地址。
2.6本地方法栈
Java虚拟机使用其他语言(例如c语言)来实现指令集解析器时,使用本地方法栈。
3.JVM的生命周期
启动:启动一个java程序时,一个JVM实例就产生了,任何一个拥有
public static void main(String[]args){}的class都可以作为JVM实例运行的启点。
运行:mian()方法作为该程序初始线程的启点,任何线程均由该线程管理。
消亡:当程序的所有非守护线程都终止时,JVM才退出;若安全管理器允许,
程序也可以使用Runtime类或者System.exit()来退出。
Java中的线程分为两种:守护线程(daemon)和普通线程(non-daemon)。
守护线程是java虚拟机自己使用的线程,比如说垃圾回收器就是一个守护
线程。也可以自己把程序设置为守护线程,main()不是守护线程。