jvm--组成及运行时数据区
一、组成:
1.共享区:
堆:存放对象,常量池,字符串常量池,
a.对象的组成:对象头+实例数据+对齐填充
b.对象头的组成:
(1)mark down:32位对象->hash25+age4+是否偏向1+锁标识2
(2)类型指针:指向metaspace的类型信息
(3)如果为数组还有数组的长度
c.对象在堆中的内存分配:
(1) 指针碰撞:如果Java堆的内存是规整,即所有用过的内存放在一边,而空闲的的放在另一边。分配内存时将位于中间的指针指示器向空闲的内存移动一段与对象大小相等的距离,这样便完成分配内存工作
(2)空闲列表:如果Java堆的内存不是规整的,则需要由虚拟机维护一个列表来记录那些内存是可用的,这样在分配的时候可以从列表中查询到足够大的内存分配给对象,并在分配后更新列表记录
d.怎样解决线程的分配冲突:
(1) CAS 自旋:采用 CAS + 失败重试来保障更新操作的原子性
(2) 本地线程分配缓存:把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在 Java 堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)。哪个线程要分配内存,就在哪个线程的 TLAB 上分 配。只有 TLAB 用完并分配新的 TLAB 时,才需要同步锁。通过-XX:+/-UserTLAB参数来设定虚拟机是否使用TLAB
e.引用:
(1)强引用--->Son son = new Son();
(2)软引用--->堆空间不足时释放,用作高速缓存。
(3)弱引用--->下次GC释放,ThreadLocal使用弱引用。
(4)虚引用-->必须配合引用链表使用,可以记录对象死亡
方法区(metaspace):存放类型信息,就是Class源信息。jdk7以后采用本机内存实现,不在占用java内存。
2.线程私有:
栈:线程运行时,里面由栈帧组成,一个方法就是一个栈帧(在加载到jvm时就已经计算出来占用空间大小了)。
(1)本地变量表:本方法需要用到的变量的列表,由槽(slot)组成可为32bit也可以为其他大小由具体虚拟机来定。this指向的当前类就是变量槽第0个位置元素,固定。
槽可能重用,导致方法中占用空间大的变量已经没用了但是还是没有被回收。
(2)操作数栈:基于栈的指令执行需要用到的逻辑处理的栈
(3)方法返回地址:记录调用者的一些信息,方便这个栈帧执行完成后返回调用方法
(4)额外信息:如锁的信息轻量级锁记录的锁持有对象的hash+age等信息,记录jvm性能等。
(5)动态链接:该栈帧属于那个方法
本地方法栈:本地方法执行的栈
程序计数器:记录程序运行到那一行
二、方法调用:
方法调用的5调指令:
invokeSpecial 调用私有方法,调用父类,构造器方法
invokestatic 调用静态方法
invokevirual 调用虚方法(final的方法也是这个指令)
invokeinterface 调用接口方法
invokeDynamic 用于java语言的动态性
1..解析: 在将*.java编译成*.class后调用逻辑已经固定了。
2.分派:--------------------->只有方法才有分派,对象的属性统一都是按照静态类型调用
静态分派:重载->采用调用方法入参的静态类型。
动态分派: 重写,运行时才知道到底执行那个对象的方法,按照实际类型调用,多态的实现
java的泛型---->檫除式泛型,只在程序源码中有,到jvm执行时就已经没有泛型信息了。
List<son> 的父类是List<? extends parent> 而不是List<parent>。还有一个泛型用法List<? super parent>
三、指令执行:
1.基于栈的指令执行(jvm等虚拟机,为了可移植性):不带参数,在内存(可逻辑映射为寄存器)中。指令多,不带参数
iconst_1
iconst_1
iadd
istore_0
#这个jvm中计算1+1的指令列表
2.基于寄存器的指令执行,带参数,在寄存器中(寄存器是cpu中的高速计算单元)。指令更少,带参数,执行更快
mov eax, 1 add eax, 1
#这是基于寄存器的指令列表

浙公网安备 33010602011771号