一、JVM
是整个Java平台的基石,是Java技术用于实现硬件与操作系统无关的关键部分,是保证用户机器免于恶意代码损害的屏障。
可以被看做是一台抽象的计算机。 有⾃己的指令集和运行时的内存区域。
与Java语⾔言并没有必然的联系。
只有特定的二进制文件格式-Class文件格式关联。
毕竟虚拟机其实只是一个程序,比我们写的hello world牛点。
二、JVM的运⾏时内存区域划分
语⾔言级别内存划分。
1. 线程私有
1.1. 程序计数器-pc 寄存器
每个jvm线程都有⾃己的pc 计数器
线程执⾏到的字节码的行号指示器,只要不是native方法, ⽤于执行过程中的循环、跳转、分⽀支、异常处理理线程恢复等。
⽣命周期与线程相同
1.2. 虚拟机栈- stack
描述的是⽅法执行的内存模型,⽅法的执行过程就是虚拟机栈的入栈与出栈
用于存储局部变量和部分过程结果(些尚未算好的结果)的数据结构。
也被用来处理动态链接、方法返回值和异常分派。
生命周期与JVM线程相同,⽅法执⾏时都会创建⼀个栈帧。
随着⽅法调⽤而创建,随着方法结束(⽆论正常还是异常完成)而销毁。
局部变量表和操作数栈都是在编译期确定,在方法的code属性中。
1.2.1. 局部变量表
存放在编译时已经确定的8种基本类型、对象引用等。空间⼤小是确定的,
在运行期间不会改变。
⽅法参数和局部变量
局部变量 没有 初始化阶段,即不会被赋零值。
1.2.2.操作数栈
类似于数据寄存器
方法开始执行时是空的, 运算过程中会有出栈入栈操作。
1.3. 本地方法栈⽤
用来⽀持native⽅法执⾏
native关键字说明其修的⽅法是一个原⽣态方法,方法对应的实现不是在当前文件,⽽是在⽤其他语⾔(如C和C++)实现的文件中
2. 线程共享
2.1. 方法区
是堆的一个逻辑部分 虚拟机启动时创建,1.8 已经开始直接使⽤用本地内存,元 空间。
存储虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。 类的 版本信息等 字段 方法 接口等。 常量池。- 运⾏行行时常量池。 类、实例例、接口初始化时⽤用 到的特殊方法。
不严谨的说,包含整个程序永远唯一的元素。
2.2. Java 堆 -heap
可供各个线程共享的运行时内存区域。
最⼤的⼀块 ⼤小可以是固定的,也可以是动态的。 虚拟机启动时创建 几乎所有对象与数组都在堆上分配。
可能会划分出多个线程私有的分配缓冲区 TLAB
2.3 直接内存
虚拟机规范外的内存区域,如NIO直接使⽤用的堆外内存。
三、内存回收特殊的内存模块-不需回收或回收效率低
线程私有的的内存:程序计数器、虚拟机栈、本地方法栈,随着线程生灭,分 配和回收都是确定的。
永生代,就是前⾯面说的方法区,回收的效率很低。 现已改为 元空间,直接使⽤用的是本地内存。回收的两个内容为:
1. 废弃常量 没有任何⼈人⽤用
2. ⽆用的类 条件比较苛刻
1. 该类的所有实例都已经被回收。
2. 加载该类的ClassLoader已经被回收
3. Class对象没有任何地方被引用,无法在任何地方通过反射访问该类
1. 堆内存分代——有针对性的采⽤不同的回收机制,有利 于内存回收
1.1. 年轻代和⽼年代
1. 年轻代对象朝生夕灭,
一般划分是 一个Eden区和两个Survivor区。2. ⽼年代对象历久弥坚
1.2. 创建对象时的分配
1. 对象优先分配到Eden区,经历一定次数的回收之后,仍然存活的对象进⼊老年代。
2. ⼤对象直接进⼊⽼年代
2. 内存回收
2.1. GC 分类 - 何时回收
1. Minor GC 发生在新生代的内存回收
当jvm无法为一个新的对象分配内存空间时会触发Minor GC,⽐如当Eden区满了,或者内存不连续。
2. Full GC 发生在⽼年代的回收
如果⽼年代没有⾜够空间,就会进行一次Full GC 对新生代和⽼年代都进行GC
2.2. 哪些对象可以回收
2.2.1. 引⽤用计数算法
为对象添加引⽤用计数器,每个引⽤用计数+1,引⽤用失效,计数-1.会有循环引⽤用.
2.2.2. 可达性分析
通过一系列列的 GC Roots 对象作为起始点,搜索所⾛走过的路路径称为引⽤用链。
当一个对象没被引⽤用的时候,就判定为可回收对象。
GC Roots:
1. 虚拟机栈中引⽤用的对象
2. 方法区中类静态属性引⽤用的对象
3. 方法区中常量引⽤用的对象
4. 本地方法栈中引⽤用的对象
3. 如何回收 - 回收算法介绍
3.1 年年轻代回收算法
3.1.1 标记-清除
标记出所有需要回收的对象
统一回收所有被标记的对象
不⾜:
效率,标记和回收的效率都不高
空间,会产生大量的离散的内存碎片
3.1.2 复制
空间换效率 新生代基本都采⽤用这种算法。
将还存活的对象复制到另一块内存上,其他的一次性清理掉。Eden和2 个 Survivor
HotSpot 默认是 8:1:1
如果 10% 不够放置存活的对象,则直接进入老年代。
3.2 ⽼年代算法
3.2.1 标记-整理
⽼年代,一般就是对象存活率比较高。 ⽼而弥坚。
与标记清理类似,但是不清理,而是让存活的对象移动到一端,