1. Java虚拟机的架构java
1.0 运行时数据区:通过编译的class文件,由ClassLoader(类加载子系统)加载后会交给执行引擎执行。在执行引擎执行过程当中,会产生一些数据,这些数据被称为运行时数据,存储这些数据的内存区域称为运行时数据区。性能优化
1.1 Java的NIO库容许Java程序使用直接内存,访问直接内存的速度优于Java堆。出于性能的考虑,读写频繁的场合会考虑使用直接内存。架构
1.2 本地方法栈和Java栈很是相似,最大的不一样在于Java栈用于Java方法的调用,而本地方法栈用于本地方法的调用。jvm
1.3 PC 寄存器: Program Counter寄存器,即:程序计数器,跟随线程的启动而建立。用于记录当前线程重在执行的字节码指令位置。【线程专有】函数
1.4 在任意时刻,一个Java线程老是在执行一个方法。若是这个方法不是本地方法,PC寄存器就会指向当前正在被执行的指令;若是这个方法是本地方法,PC寄存器的值是undefined。性能
1.5 JVM内存结构的五大区域:Java栈(虚拟机栈)、本地方法栈、PC寄存器、方法区、Java堆。其中,Java栈、本地方法栈、PC寄存器是线程专有的。优化
2.Java堆spa
2.1 结构:根据垃圾回收机制的不一样,Java堆可能有不一样的结构。最多见的一种结构是将Java堆分为新生代和老年代。线程
2.2 流程:3d
在绝大多数状况下,对象首先会分配到eden区,在一次新生代回收后,若是对象还存活,会进入s0或则s1区;以后,每经历一次新生代回收,若是对象还存活,则年龄加1。年龄达到必定条件后,会被认为是老年对象,进入老年代。
3.Java栈(虚拟机栈)
虚拟机栈是Java方法执行的内存结构,虚拟机会在每一个方法执行时建立一个“栈帧”,用于存储局部变量表,操做数栈等信息。当方法执行完毕后,该栈帧会从虚拟机栈中出栈。
3.1栈帧出入栈【函数调用】过程
3.1.1 出栈顺序:先入后出
3.1.2 每次函数调用的数据都是经过Java栈传递的。
3.1.3 Java栈中保存的主要内容是是栈帧。[栈帧中保存着当前函数的局部变量、操做数、中间运算结果等数据]。
3.2 Java栈基本构架
3.2.1 栈帧至少包含局部变量表、操做数栈和帧数据区。
3.4 当栈空间不足时,函数调用没法继续,系统会抛出StackOverflowError栈溢出错误。【能够经过-Xss设置线程的最大栈空间】
3.5 StackOverflowError演示【递归死循环】
package com.blueStarWei.jvm; public class StackOverflowError { private static int count = 0; public static void main(String[] args) { try{ recursion(); }catch(Throwable e){ System.out.println("deep of calling : "+count); e.printStackTrace(); } } public static void recursion(){ count++; recursion(); } }
3.5.1 日志输出
//根据-Xss配置的参数不一样,被调用的次数会不一样 deep of calling : 31661 java.lang.StackOverflowError at com.blueStarWei.jvm.StackOverflowError.recursion(StackOverflowError.java:18)
4.方法区
4.1 在JDK1.六、1.7中,方法区能够理解为永久区(Permanent).。JDK1.8中,永久区被完全移除,取而代之的是元数据区(堆外的直接内存)
4.2 方法区是被全部线程共用的内存空间,在JVM启动时建立.
4.3 运行时常量池 : 除了每一个类或接口中定义的常量,它还包含了全部对方法和字段的引用。所以当须要一个方法或字段时,JVM经过运行时常量池中的信息从内存空间中来查找其相应的实际地址。
4.4 设置参数
参数 | 做用 | 备注 |
-XX:PremSize | 设置永久区初始化空间 | |
-XX: MaxPremSize | 设置永久区的最大空间 | 默认64MB |
-XX:MaxMetaspaceSize | 设置元数据区的最大空间 | 若是不指定大小,虚拟机会耗尽全部可用的系统内存 |
4.5 垃圾收集在这个区域是比较少出现的,这区域的内存回收目标重要是针对常量池的回收和类型的卸载。
5. 局部变量表
5.1 槽位复用
5.1.1 含义:若是局部变量A超出其做用域,那么在其做用域以后的局部变量B会复用A的槽位。
5.1.2 优势: 节省资源
5.1.3 注意:若是A做用域以后没有新的变量,A不会从局部变量表中移除【可使用-XX:+PrintGC查看GC信息,判断是否触发GC】
//局部变量a仍然存在于局部变量表中,不会触发GC public void localGC1(){ { byte[] a = new byte[6*1024*1024]; } System.gc(); } //局部变量a的槽位已经被局部变量b复用,触发GC[回收局部变量a] public void localGC2(){ { byte[] a = new byte[6*1024*1024]; } int b = 0; System.gc(); }
6.参考文献
6.1 《实战Java虚拟机 - JVM故障诊断与性能优化》