JVM
2021-07-29 17:29:18 5 举报
AI智能生成
JVM
作者其他创作
大纲/内容
Java栈
不存在GC
保存
8大类型
引用对象
实例方法
运行原理
栈帧
栈满
StackOverflowError
概念
运行Java字节码(.class)的虚拟机
一次编译,永久执行
相关图片
内存布局
内存区域
私有区
程序计数器
1. 字节码解释器改变之-行号指示器(指向下一条指令,依次读取指令)
2. 多线程下记录当前线程执行的位置,以为线程间切换恢复到正确位置
3. 执行native 方法时,记录的是 undefined 地址
唯一不会出现OOM的内存区域
存储的是字节码文件的行号,分配时即知
一块较小的内存空间
虚拟机栈
一个个的栈帧
(每个栈帧-->Java方法)
(每个栈帧-->Java方法)
局部变量表、操作数栈、
动态链接、方法返回信息
动态链接、方法返回信息
局部变量表
一般说的栈内存
基本类型
引用类型
方法参数和局部变量
代表一次方法调用直至执行完成的过程 --> 入栈出栈
StackOverFlowError 和 OutOfMemoryError。
本地方法栈
Native方法服务
1.私有是为线程间切换能恢复到正确的执行位置
2.3私有是为了局部变量等不被其他线程访问到
共享区
堆
存放Java对象实例,最大一块内存
GC主要管理的区域:GC堆
堆空间的基本结构:
eden区、s0区、s1区都属于新生代(8:1:1)
老年代
⼤对象直接进⼊⽼年代
⻓期存活的对象将进⼊⽼年代
大部分情况,对象都会首先 在 Eden 区域分配。
在一次新生代垃圾回收后,如果对象还存活,则会进入 s0 或者 s1,
并且对象的 年龄还会加1 (Eden >> Survivor 区后对象的初始年龄变为1),
当它的年龄增加到一定程度(默认为15 岁),就会被晋升到老年代中。
在一次新生代垃圾回收后,如果对象还存活,则会进入 s0 或者 s1,
并且对象的 年龄还会加1 (Eden >> Survivor 区后对象的初始年龄变为1),
当它的年龄增加到一定程度(默认为15 岁),就会被晋升到老年代中。
默认晋升年龄并不都是 15,
这个是要区分垃圾收集器的,CMS 就是 6.
这个是要区分垃圾收集器的,CMS 就是 6.
方法区(<JDK1.8)
类信息、常量、静态变量
堆的逻辑部分
运行时常量池(字符串String)
构造函数(所有定义的方法信息)
永久代
永久代是HotSpot中的方法区实现方式
是HotSpot中的概念
是Java虚拟机中的定义
参数
初始大小
-XX:PermSize=N
最大大小
-XX:MaxPermSize=N(无法调整)
元空间(>=JDK1.8)
参数
初始大小
-XX:MetaspaceSize=N
最大大小
-XX:MaxMetaspaceSize=N
使用直接内存
最大内存受本机可用内存控制
直接内存(非运行时)
native
修饰的方法说明Java的作用范围达不到了
调用底层C,C++
会进入本地方法栈
本地接口JNI
扩展Java的使用(融合不同语言)
专门在内存区域中开辟了本地方法栈
操作系统(软件)
JRE
硬件体系(Intel,)
对象访问定位
句柄
在堆中分配出句柄池,保存引用地址
稳定
指针
对象地址
速度快
无用
常量
运行时常量池主要回收废弃常量
废弃:没有任何String对象引用该常量
无用类
方法区主要回收无用类
1.该类所有实例对象均被回收
2.加载该类的classLoader已经被回收
3.该类对应的Class对象没有在任何地方被引用
GC root
可达性算法
标记当前时刻存活的对象!
通过GC Root 找出所有活的对象,
下所有的没有标记的对象就是需要回收的对象。
下所有的没有标记的对象就是需要回收的对象。
从GC Root节点所⾛过的路径称为引⽤链,
当⼀个对象到 GC Roots 没有任何引⽤链相连的话,
则证明此对象是不可⽤的。
当⼀个对象到 GC Roots 没有任何引⽤链相连的话,
则证明此对象是不可⽤的。
垃圾收集算法
标记-清除算法
最基础的算法
标记所有要回收的对象
问题
效率问题
空间问题
清除后产生大量不连续的碎片
复制算法
解决效率问题
将内存分为大小相同两块
清除后复制还存活对象到另一块,全部清除已使用块
适用于新生代
标记-整理
标记,然后整理存活对象向一端移动,清除边界外对象
适用于老年代
分代收集算法
目前都采用的
分代就是为了提升GC效率
为了节省 内存和解决内存碎片的问题
将对象存活期分为几代
新生代
复制算法
老年代
标记-清除
垃圾回收器
Serial收集器
单线程收集器了
只会使用一条垃圾收集线程去完成垃圾收 集工作,
它在进行垃圾收集工作的时候必须暂停其他所有的工作线程
它在进行垃圾收集工作的时候必须暂停其他所有的工作线程
ParNew收集器
Serial收集器的多线程版本
新生代采用复制算法,老年代采用标记-整理算法。
CMS收集器
Concurrent Mark Sweep
以获取最短回收停顿时间为目标的收集器
真正意义上的并发收集器,
实现了让垃圾收集线程与用户线程(基本上)同时工作。
实现了让垃圾收集线程与用户线程(基本上)同时工作。
标记-清除”算法
G1收集器
G1 (Garbage-First)是一款面向服务器的垃圾收集器
主要针对配备多颗处理器及大容量内存的机器.
以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征.
以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征.
初始标记 并发标记
最终标记 筛选回收
最终标记 筛选回收
维护了一个优先列表,每次根据允许的收集时间,
优先选择回收价值最大的Region
优先选择回收价值最大的Region
触发YGC和FGC
当一个新的对象来申请内存空间的时候,如果Eden区无法满足内存分配需求,则触发YGC
使用中的 S区和Eden区存活对象送到未使用的S区,
如果YGC之后还是没有足够空间,则直接进入 老年代分配,
如果老年代也无法分配空间,触发FGC,FGC之后还是放不下则报出OOM异常。
Java 创建对象过程
1. 类加载检查
new,去常量池中定位该符号引用
类加载过程
加载
通过全类名获取二进制字节流
字节流转换为方法去运行的数据结构
在方法区生成Class对象,作为访问入口
验证
准备
为静态变量、常量赋默认值
解析
初始化
执行static代码块(cinit)进行初始化,如果存在父类,先对父类进行初始化
2. 分配内存
为新生对象从堆中分配内存
CAS+失败重试
CAS:乐观锁
每次不加锁是假设没有冲突
TLAB
每一个线程预先在Eden区分配一块儿内存
线程专用的内存分配区域。
线程专用的内存分配区域。
Thread Local Allocation Buffer
线程本地分配缓存区
线程本地分配缓存区
分配方式
指针碰撞
堆内存规整:没有碎片->标记-整理算法
空闲列表
堆内存不规整:没有碎片->标记-清理算法
3. 实例变量赋默认值
分配到内存空间的都初始化,
保证在编写时可不用初始化
保证在编写时可不用初始化
4. 设置对象头
该对象是哪个类的实例
类的元数据信息
对象的Hash码
对象的GC分代
对象实例
对象头、实例数据组成
其中对象头包括markword和类型指针,如果是数组,还包括数组长度;
5. 执行init方法
new->init方法,对象真正产生
类加载器
bootstrapClassLoader
启动类(根)加载器:/lib
C++实现
最顶层加载器
ExtensionClassLoader
扩展类加载器:/lib/ext
AppClassLoader
应用程序加载器
面向用户
classpath下jar与类
双亲委派机制
自底向上检查该类是否被加载
自顶向下尝试加载该类
Error:找不到main方法
用处
保证Java程序的稳定运行
避免类的重复加载
保证核心API不被篡改
沙箱机制
Java安全模型的核心
限制程序运行的环境
就是将 Java 代码限定在虚拟机(JVM)特定的运行范围
并且严格限制代码对本地系统资源访问
CPU
内存
文件系统
网络
JMM内存模型
线程都是从主内存中读取共享变量到工作内存来操作,
完成之后再把结果写会主内存
完成之后再把结果写会主内存
happens-before
前一个操作的结果可以被后续的操作获取。
讲白点就是前面一个操作把变量a赋值为1,那后面一个操作肯定能知道a已经变成了1。
讲白点就是前面一个操作把变量a赋值为1,那后面一个操作肯定能知道a已经变成了1。
书籍
深入理解Java虚拟机
0 条评论
下一页