按照Java虚拟机规范,从class文件到加载到内存中的类,到类卸载出内存为止,它的整个生命周期包括如下7个阶段:
加载:
类的加载指的是将类的.class文件中的二进制数据读取到内存中,存放在运行时数据区的方法去中。
在加载的过程中。jvm需要做三件事:
1:通过类的全限定名来获取此类的二进制文件。
2:将这个字节流所对应的静态存储结构转换为方法区运行时数据结构
3:在内存中生成一个Java.lang.class对象,作为方法区这个类的入口
验证:
这一阶段的目的是确保Class文件的字节流中包含的信息符合当前虚拟机的要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。包含(文件格式验证,元数据验证,字节码验证,符号引用验证);
准备:
准备阶段就是为非final修饰的静态变量 分配内存并设置初始值。因为静态变量和类绑定在一起的。并不需要初始化类对象访问,所以就这个静态变量放在 方法区中。
解析:
Java虚拟机将常量池内的符号引用替换为直接引用的过程。
符号引用:符号引用是一组符号来描述所引用的目标,符号引用可以任何形式的字面量。只要是使用时可以准备的定位到目标即可。
直接引用:直接可以定位到目前的指针,相对偏移
量或者一个能够定位到内容的句柄。
初始化:
- 初始化阶段,主要是为静态变量赋予正确的初始值
- 在初始化阶段,开始执行Java代码。初始化阶段重要的工作是执行类的初始化方法clinit().
从jvm层面分析一个方法是如何执行的。
首先。找到这个类Application。类加载器加载。将这个类信息加载在 元空间空。然后将 执行main方法就是开启一个main 线程,将这个 方法 加入对应的 虚拟机栈栈底。然后在加对应的load方法加入对应的虚拟机栈头。将对应的config变量是方法的内部变量也压入对应的方法栈中,将对应的new Config()对象 压入对应的 堆中。然后将方法执行完。栈帧指向移动,方法执行完就会出栈。
对应的类信息都是元空间,已经对应的静态常量。常量池都是在 元空间中。
虚拟机栈的特点以及作用:
1:线程私有。
2:方法执行会创建对应的栈帧。然后将对应的局部变量表等。
3:方法执行进入虚拟机栈,方法执行后出栈。先进后出。
4:栈深度大于虚拟机栈深度时。会报错StackOverflowError.
5: 栈需要扩展而无法申请对应的空间而OOM(比较少见的),hotspot是没有的。(当虚拟机的栈内存允许动态扩展,当扩展栈容量无法申请到足够内存是,将抛出OOM异常。但是hotspot虚拟机不支持栈的自动扩展)
6:随着线程而生,随线程而死
7: 该区域不存在gc。
本地方法栈的特点:
1、与虚拟机栈类似。
2、区别在于本地方法为Native方法提供
3、有StackOverFlowError 和OOM
4、随线程而生,随线程而死
5、GC不会回收
元空间:
1:在jdk1.8以后才出现元空间的概念,叫做 永久代/方法区。
2:元空间与java堆类似,是线程共享的内存区域。
3:储存被加载的类信息,常量,静态变量,常量池
4:元空间采用的是本地内存,本地内存有多少空间,他就可以扩展到多大空间
-XX:MetaspaceSize=20M -XX:MaxMetaspaceSize=100M
5:元空间不足时,就容易发生OOM
6:元空间很少有GC垃圾收集,一般该区域回收苛刻。能回收的信息比较少。
堆:
1:线程共享的一块区域。
2:虚拟机启动时创建
3:存放所有实列或者数组
4:可分为新生代,老年代
5:通过xms,xmx调节堆大小
程序计数器:
1、程序计数器是一块比较小的内存空间
2、是当前线程执行的字节码的行号指示器
3、java多线程执行时,每个线程都有一个独立的程序计数器,各条线程之间的程序计数器互不影响。
4、该区域不存在OOM
5、该区域不会被GC
说出几个常用的核心参数:
xms 初始化堆大小 xmx堆的最大的大小
-XX:metaspaceSize 初始化元空间大小
-XX:MaxmetaspaceSize: 申请元空间的最大
-XX:SurvivorRatio =8 设置edem去和survivor去大小的比列 默认8:1:1
-XX:MaxTenuringThreshold = 5 年龄阈值