JVM基本结构:
- 类加载器:类加载器主要负责从文件系统或网络中加载Class文件,加载的类信息存放与方法区中。有三种默认使用的类加载器:Bootstrap类加载器、Extension类加载器和System类加载器(或者叫作Application类加载器)。
- 方法区(永久区):方法区也叫永久区,它是被线程共享的。方法区存储类加载器加载的类信息、常量、静态变量方法区的大小决定可以存储多少个类。(在java8中,永久区(PermGen)被元数据区(Metaspace)取代, 元数据区和直接内存都属于本地内存空间)
- Java堆:Java堆在虚拟机启动时创建,是java程序最主要的内存工作区。几乎所有的Java对象实例都存储在Java堆中。对空间是线程共享的。-Xms -Xmx -Xmn
- 直接内存:Java NIO库允许Java程序使用直接内存。它是Java堆外的、直接向系统申请的内存空间。访问直接内存的速度会优于Java堆。因此,读写频繁的操作会考虑使用直接内存。
- 垃圾回收系统(GC):垃圾回收器可以对方法区、Java堆和直接内存进行回收。其中Java堆是垃圾回收器的主要工作区。
- Java栈:Java栈是线程私有的,一个线程的Java栈在线程创建时被创建,java栈中保存着帧信息。Java栈中保存着局部变量、方法参数、操作数栈、动态链接、方法返回地址。-Xss
- 本地方法栈:和Java栈类似,最大的不同在于Java栈用于方法调用,而本地方法栈则用于本地方法调用(native),本地方法一般用C语言编写。
- PC寄存器(计数器):PC寄存器是线程私有的,存放各种指针,用于线程选取下一条执行命令。在任意时刻,一个Java线程总是在执行一个方法,这个正在被执行的方法称为当前方法,如果当前方法不是本地方法,PC寄存器就会指向当前当前正在执行的指令;如果当前方法是本地方法,PC寄存器就是undefined。
- 执行引擎:执行JVM的字节码文件。
JAVA8取消了永久代, 但是方法区还是存在的,因为方法区只是一个规范, java8中将它的实现改成了元空间。原来永久代中的类元信息(class metadata)转移到了本地内存中(native memory);永久带中的字符串常量(interned strings)和静待变量(class static variables)转移到了java heap; 永久代参数PermSize、MaxPermSize 变成 MetaspaceSize、MaxMetaspaceSize
java8用元数据区代替永久代的原因:
- 字符串在永久代中,容易出现性能问题和内存溢出
- 类方法的信息等比较难确定其大小, 因此永久代的大小指定比较困难, 太小容易出现永久代溢出,太大容易出现老年代溢出
- 永久代会为GC带来不必要的复杂度, 且回收效率比较低
现在JVM的基本构成和各部分的作用已经知道了,再来看看JVM是如何执行工作的。
JVM工作流程:
JVM在运行时可分为五大模块: 类装载子系统、运行时数据区(系统的内存空间)、执行引擎、本地方法接口和垃圾收集模块。
- Java代码被编译成Class文件,然后被类加载器加载,类加载器将加载后的信息存放在方法区等内存空间中。
- 执行引擎执行加载进内存空间的字节码文件,而PC寄存器用于存放执行的指令,便于执行引擎执行。
- 执行期间如果需要调用本地方法,则通过本地方法栈调用。
- 而垃圾收集器则在JVM的整个过程中起作用,主要用于回收内存空间,准确的说是主要回收Java堆空间。