JVM面试图解
2023-10-10 19:37:49 1 举报
JVM面试图解
作者其他创作
大纲/内容
静态变量
局部变量表
对象头
TLAB
本地方法栈
Eden (8/10)
动态连接
程序计数器Programe Counter Register
加载
类加载过程做了三件事:1.通过一个类的全限定名来获取定义此类的二进制字节流 - 从zip包获取 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
Bootstrap ClassLoader
常量池
元空间/方法区
Application ClassLoader
类加载过程
returnAddress
堆
方法返回地址
类地址:$JAVAHOME/lib/ext/*.jar系统参数:java.ext.dirs运行时指定:-Djava.ext.dirs
方法区Method Area
Minor GC回收
4.1 通过直接指针访问对象
执行引擎Execution Engine
操作数栈
3.Java堆和方法区内存结构
对象堆内存分配
栈帧-MethodB
虚拟机栈
Java运行时数据区Runtime Data Area
类加载
MethodA
句柄池
老年代(2/3)
实例数据
即时编译器编译后的代码
User ClassLoader
类的生命周期
From Survivors0 (1/10)
如果使用句柄访问的话,那么Java堆中将会划分出一块内存来作为句柄池reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息,
.Java文件
老数据
本地库接口Native Interface
6.对象的创建
8大基本类型
1.程序计数器:可以看作当前线程所执行的字节码的行号指示器2.虚拟机栈:描述的是Java方法执行的内存模型: - 每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。 - 每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。3.本地方法栈: - 与虚拟机栈类似,不过却是为虚拟机使用到的Native方法服务 - HotSpot虚拟机将虚拟机栈和本地方法栈合二为一4.方法区: - 存放已被虚拟机加载的类的类信息、常量、静态变量、即时编译器编译后的代码 - 对HotSpot虚拟机来说,也称为永久代(Permanent Generation)。 - jdk1.6及之前:有永久代,常量池在方法区 - jdk1.7:有永久代,但已逐步“去永久代”,常量池转移到堆中 - jdk8及之后:无永久代,常量池在元空间5.堆: - 存放几乎所有的对象实例和数组,GC的主要区域 - 从内存回收的角度,可划分为新生代和老年代,可进一步细分为Eden空间、From Survivor空间、To Survivor空间 - 从内存分配的角度,可能划分出多个线程私有的分配缓冲区(TLAB)
执行<init>
线程间共享
虚拟机栈VM Stack
To Survivors1 (1/10)
[数组长度]
7.类加载
数组
初始化
句柄
iload 1
MethodB
连接
markword
新生代(1/3)
1.虚拟机遇到new指令时,开始创建对象2.首先,进行类加载检查: - 检查new指令的参数是否能在常量池中定位到一个类的符号引用 - 并且检查这个符号引用代表的类是否已被加载、解析和初始化过;如果没有,那必须先执行相应的类加载过程3.然后,为新生对象分配内存: - 为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来,因为对象所需内存的大小在类加载完成后便可完全确定(类元数据信息中记录了对象大小) - 分配内存需要考虑两个问题 - 分配方式 - 选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定 - 指针碰撞(堆规整,Serial、ParNew) - 空闲列表(堆不规整,CMS) - 线程安全 - 同步:CAS+失败重试 - TLAB:-XX:+/-UseTLAB4.接着,将实例数据初始化为零值,主要是成员变量的数据类型所对应的的零值5.再就是,对象头设置,设置MarkWord、类型指针6.最后,执行<init>方法,也就是执行对象的构造器
reference中存储的直接就是对象地址
32位
类型指针
reference
对齐填充
堆Heap
对象
6大基本类型
栈帧
线程私有
我们从对象的初始化过程来分析堆和方法区:(1)首先,类加载的时候操作的是方法区,在加载阶段完成后, - .class文件的二进制字节流就会按照虚拟机所需的格式(数据存储格式没有规定)存储在方法区中(即时编译器编译后的代码?) - 然后会在内存中实例化一个java.lang.Class类的对象(没有明确规定是在堆中,HotSpot 将Class对象存在方法区中),这个对象将作为程序访问方法区中的这些类型数据的外部接口(类元数据?)(2)在准备阶段,为常量赋值,为类变量(静态变量)赋类型零值,发生在方法区(3)在初始化阶段,执行<cinit>方法,主要是执行类变量赋初始值、静态语句块(4)在对象初始化的时候,主要操作的是堆内存,会把一块确定大小的内存从Java堆中划分出来,然后为实例变量赋类型零值,然后设置对象头,然后执行构造方法
Class对象(类元数据)
4.2 通过句柄访问对象
8.垃圾回收机制
准备
程序计数器
类加载检查
Extension ClassLoader
验证
.Class文件
1.Java运行时数据区
栈帧-MethodA
卸载
大对象直接进来
new 指令
编译
MinorGC回收
双亲委派模型
解析
初始化为零值
类地址:$CLASSPATH系统参数:java.class.path运行时指定: -classpath 或-Djava.class.path
类地址:$JAVAHOME/lib/*.jar系统参数:sun.boot.class.path运行时指定: -Xbootclasspath
4.对象的访问定位
所属方法的符号引用
本地方法栈Native Method Stack
15次没有回收掉
实例池
iload 0
使用
5.对象的内存结构
线程
到对象类型数据的指针
类加载时机
到对象实例数据的指针
本地方法库Native Libraries
对象头设置
调用
2.虚拟机栈的内存结构
0 条评论
下一页