JVM和GC原理
2022-05-04 10:51:03 13 举报
AI智能生成
登录查看完整内容
为你推荐
查看更多
Java内存介绍,jvm和垃圾回收
作者其他创作
大纲/内容
javac
代码编译
class
jar
war
zip
加载在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据的入口
文件格式验证
元数据验证
字节码验证
符号引用验证
验证确保 Class 文件的字节流中包含的信息是否符合当前虚拟机的要求并且不会危害虚拟机自身的安全
准备为类变量分配内存,准备初始值对final的静态字面值常量直接赋初值
符号引用符号引用与虚拟机实现的布局无关,引用的目标并不一定要已经加载到内存中。各种虚拟 机实现的内存布局可以各不相同,但是它们能接受的符号引用必须是一致的,因为符号引 用的字面量形式明确定义在 Java 虚拟机规范的 Class 文件格式中。CONSTANT_Class_infoCONSTANT_Field_infoCONSTANT_Method_info
直接引用直接引用可以是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。如果有 了直接引用,那引用的目标必定已经在内存中存在。
解析将符号引用转换成直接引用
连接
不初始化的场景(不初始化不代表不执行上面的加载和链接步骤)通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。定义对象数组,不会触发该类的初始化。常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类。通过类名获取 Class 对象,不会触发类的初始化。通过 Class.forName 加载指定类时,如果指定参数 initialize 为 false 时,也不会触发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。通过 ClassLoader 默认的 loadClass 方法,也不会触发初始化动作。
初始化为静态变量赋值
使用
卸载
类的生命周期
主动引用加载(loading)阶段,java虚拟机规范中没有进行约束,但初始化阶段,java虚拟机严格规定了有且只有如下5种情况必须立即进行初始化(初始化前,必须经过加载、验证、准备阶段)使用new实例化对象时,读取和设置类的静态变量、静态非字面值常量(静态字面值常量除外)时,调用静态方法时。对内进行反射调用时。当初始化一个类时,如果父类没有进行初始化,需要先初始化父类。启动程序所使用的main方法所在类当使用1.7的动态语音支持时。
被动引用通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。定义对象数组和集合,不会触发该类的初始化类A引用类B的static final常量不会导致类B初始化(注意静态常量必须是字面值常量,否则还是会触发B的初始化)
类加载的时机
隐式加载创建类对象使用类的静态域创建子类对象使用子类的静态域在JVM启动时,BootStrapLoader会加载一些JVM自身运行所需的class在JVM启动时,ExtClassLoader会加载指定目录下一些特殊的class在JVM启动时,AppClassLoader会加载classpath路径下的class,以及main函数所在的类的class文件
显示加载ClassLoader.loadClass(className),只加载和连接、不会进行初始化font color=\"#ffb74d\
类加载的方式
类加载当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载、连接、初始化3个步骤来对该类进行初始化。如果没有意外,JVM将会连续完成3个步骤,所以有时也把这个3个步骤统称为类加载或类初始化
解释执行
编译执行
执行class
Java代码执行
指向虚拟机字节码指令的位置
唯一一个无OOM的区域
程序计数器PC
虚拟机栈和线程的生命周期相同
一个线程每调用一次方法就创建一个栈祯
本地变量表
操作数栈
运行时常量池的引用
返回地址
栈祯的结构
线程请求的栈深度大于JVM所允许的深度 StackOverflowErroe
无法申请足够的内存 OOM
异常
虚拟机栈 VM stack
本地方法栈Native Method Stack
线程私有
运行时常量池
永久代存储被JVM加载的类信息,常量,静态变量,即时编译后的代码java8之后被元数据取代,使用直接内存,字符串池和静态变量放到堆中管理
eden
from survivor
to survivor
新生代复制算法
老年代标记清除算法
堆font color=\"#ffb74d\
线程共享
不受jvm gc 管理
直接内存
内存空间
堆上分配
TLAB
栈上分配
内存分配
那些内存需要回收
什么时候回收
怎么回收
GC要做的三件事?
循环引用问题
引用计数法Reference Count
VM 栈中的引用
方法区中的静态引用
JNI中的引用
根搜索算法GC Roots tracing通过一系列成为GC roots的点作为起点,向下搜索当一个对象到任何GC roots没有引用链,说明起已经死亡
哪些对象已经死亡
新生代,朝生夕死
复制算法copying效率高,无碎片化,空间被压缩,利用率不高如果存活对象增多,效率会变低
标记需要清理的对象
清除对象
标记清除Mark-Sweep内存碎片化
标记
将待清除的移动到另外一边
清理边上的对象
标记整理Mark-Compact
分代收集
垃圾回收算法每次清除新生代,年龄+1.大于15直接放入老年代对象占用内存太大,直接到老年代老年代放不下,触发Major GC
单线程,复制算法,新生代,对于单核的处理器,少了上下文切换,效率高
Serial
多线程版本的复制算法,在回收stop the world时是多线程的
ParNew
多线程复制算法,关注吞吐吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)), 高吞吐量可以最高效率地利用 CPU 时间,尽快地完成程序的运算任务,主要适用于在后台运算而不需要太多交互的任务
Parallel Scavenge
老年代,单线程标记整理算法与新生代Parallel Scavenge搭配使用作为老年代CMS的备用收集器
Serial Old
Parallel Scavenge的老年代版本,多线程标记整理算法。在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老代的 Serial Old 收集器,只 能保证新生代的吞吐量优先,无法保证整体的吞吐量,Parallel Old 正是为了在年老代同样提供吞 吐量优先的垃圾收集器,如果系统对吞吐量要求比较高,可以优先考虑新生代 Parallel Scavenge 和年老代 Parallel Old 收集器的搭配策略。
Parallel Old
只标记GC Roots能直接关联的对象,速度很快 stop the world
初始标记
进行GC roots跟踪过程,和用户线程一起工作,不需要stw
并发标记
修正并发标记时,因用户线程继续运行而导致标记产生的变动的那一部分标记记录,STW
重新标记
并发清除对象,和用户线程一起工作,不需要STW,时间比较长
并发清除
CMS并发标记清除老年代多线程标记清楚算法,以获取最短停顿时间
G1
垃圾回收器
Xms
Xmx
Xmn
-XX:PrintCDetails
-XX:SurvivorRatio=8
-XX:PretenureSizeThreshold=xxx
-XX:MaxTenuringThreshold
-XX:-HandlePromotionFailure
参数
内存回收GC
jconsole
visualvm
jstat
jmap
MAT
内存状况分析
内存管理
Subtopic
JMM
JVM
0 条评论
回复 删除
下一页