一、什么是 JVM
-
JVM(Java Virtual Machine):Java 虚拟机,用来执行 class 文件、保证 Java 语言跨平台
-
Java 虚拟机可以看做是一台虚拟的计算机,和真实的计算机一样,它有自己的指令集以及各种运行时内存
-
JVM 就是一个字节码翻译器,它将字节码文件翻译成各个系统对应的机器码,确保字节码文件能在各个系统上正确的运行
二、JVM 体系结构
大概中文图:
主要分为三大层:
1. 类加载器子系统(Class Loader SubSystem)
在运行程序时首次运行类时进行加载->连接->初始化
(1) 加载(Loading):加载类文件,通过引导类加载器、扩展类加载器、应用程序类加载
器三个加载器来完成类的加载
(2) 连接(Linking):连接操作,验证(验证字节码是否正确)、准备(为静态变量分配内存
空间和默认值)、解析
(3) 初始化(Initialzation):初始化所有静态变量并执行静态代码块
2. 运行时数据区(Runtime Data Areas)
(1) 方法区(Method Area):存储所有类级别的数据,方法区在 JVM 中只有一个是多个线
程所共享的
(2) 堆区(Heap Area):所有的对象、变量、数组都存在在该区域堆区在 JVM 中只有一个
是多个线程所共享的
(3) 虚拟机栈(Stack Area):线程私有的,每个线程会创建单独的运行时栈,每个方法
调用会在运行时栈中创建一个栈帧,局部变量都存在于栈内存中;
(4) 程序计数器(PC Registers):线程安全的,每个线程都有单独的计数器,主要用于保
存当前要执行的指令号,一旦指令执行,计数器将更新到下一条指令号
(5) 本地方法栈(Native Method stack):线程安全的,每个线程单独创建自己的本地方
法区,主要用于保存本地方法信息
运行时数据区:
3. 执行引擎(Execution Engine)
(1) 解释器(Interpreter):作用读取字节码,并逐一执行
(2) 即时编译器(JIT Compiler):由于一段代码被多次调用时,都需要解释执行,即时
编译期可以将这样的字节码编译为本地代码,用于多次的重复调用提高系统性能
(3) 垃圾回收器(Garbage Collection): 收集并删除未引用的对象,可以调用
System.gc()来触发垃圾回收器进行垃圾回收,垃圾回收器只回收使用 new 关键字创
建的对象,使用 finalize 方法清理其他对象
(4) 本地方法接口(Native Method Interface):与本地方法库进行交互,提供执行引擎
所需要本地库
(5) 本地方法库(Native Method Library):执行引擎所需要本地库的集合
三 . 运行区 对象解释
1 程序计数器(Program Counter Register)
作用:
-
保存当前要执行指令的地址(指令号),一旦指令执行,计数器将更新到下一条指令的地址(指令号)
-
每个线程都有单独的计数器,它属于线程私有的,用于存储当前线程要执行的代码指令地址
(行号)程序计数器是线程安全的
JVM 指令通过 javap –v test.class 反解析获得(javap 反解析工具,它的作用就是
根据 class 字节码文件,反解析出当前类对应的 code 区(汇编指令)、本地变量表、异
常表和代码行偏移量映射表、常量池等等信息。)
执行过程:
1. 计数器读入要执行的 JVM 指令号
2. CPU 获取计数器中的指令号
3. CPU 根据从计数器中获取的指令号执行相对应的指令
4. 计数器更新要执行的 JVM 指令号
2、虚拟机栈(Stack Area)
-
虚拟机栈就是我们常说的栈
-
虚拟机栈是 Java 方法执行的内存模型
-
每个执行的线程都有自己的虚拟机栈(系统为当前线程分配的内存空间),它是线程私有
-
的程序执行是通过方法调用来实现的,在虚拟机栈中,每个方法都对应了一个栈帧
-
每个线程只能有一个活动栈帧,对应着当前正在执行的方法,该栈帧处于栈顶
-
虚拟机栈会发生内存溢出
-
每个栈帧中包含:局部变量表、操作数栈、动态链接、方法返回值等信息
3 本地方法栈
使用 native 修饰的方法为本地方法,它和 Java 方法不同,本地方法不是有 Java 实现,
而是会进入本地方法栈 调用本地方法本地接口 JNI (Java Native Interface) ,本地方法 有本地的动态库提供,可以是任意的语言实现,如 C、C++;
4 堆(Heap)
堆是 JVM 中占用内存最大的一块
-
堆是被所有线程所共享的内存区域,在虚拟机启动时创建
-
堆是用来存放实例对象和数组的内存区域
-
堆是垃圾收集器管理的主要区域
-
堆在逻辑上分为“新生代”和“老年代”,垃圾收集器对这两个区所使用的回收策略也不一样
-
新生代又分为 Eden 和 Survivor 区。Survivor 区由 FromSpace 和 ToSpace 组成。Eden 区占大容量,Survivor 两个区占小容量,默认比例是 8:1:1。
新生成的对象首先存放在新生代的 Eden 区,当 Eden 区空间满了,触发 Minor GC 清理 Eden 区的对象,存活下来的对象转移到 Survivor 的 FormSpace 区,FormSpace 区满后触发执行 Minor GC 清理 FormSpace 中的对象,在将存活的对象转移到 ToSpace 区,这样保证了在一段时间内总有一个 Survivor 区是空的,经过多次 Minor 后仍然存活的的对象转移到老年代中。 老年代存储长存活的对象,占满时会触发 Major GC 或 Full GC 对整个堆空间进行清理,GC 期间会停止所有线程等待 GC 完成,所以对响应要求高的应用尽量减少发生 Major GC,避免响应超时。
通过分带将对象根据存活概率进行分类,对存活时间长的对象,放到固定区,从而减少扫描垃圾时间及 GC 频率。针对分类进行不同的垃圾回收算法
Minor GC : 清理年轻代
Major GC : 清理老年代
Full GC : 清理整个堆空间,包括年轻代和永久代
所有 GC 都会停止应用所有线程。
堆的所占用的内存大小是可以扩展的,使用“-Xms”和“-Xmx”来控制堆的最小和
最大内存
会放生内存泄漏堆的常用参数调节:
参数 | 描述 |
---|---|
-Xms | 堆内存初始大小,单位 m、g |
-Xmx(MaxHeapSize) | 堆内存最大允许大小,一般不要大于物理内存的 80% |
-XX:PermSize | 非堆内存初始大小,一般应用设置初始化 200m,最大 1024m 就够了 |
-XX:MaxPermSize | 非堆内存最大允许大小 |
-XX:NewSize(-Xns) | 年轻代内存初始大小 |
-XX:MaxNewSize(-Xmn) | 年轻代内存最大允许大小,也可以缩写 |
-XX:SurvivorRatio=8 | 年轻代中 Eden 区与 Survivor 区的容量比例值,默认为 8,即 8:1 |
-Xss | 堆栈内存大小 |
5方法区 Method Area
方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,简单说,所有定义的方法的信息都保存在该区域,此区域属于共享区间;
静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关.


205906125" style=“zoom:67%;” />

