JVM 基础总结

1.Java 虚拟机运行时数据区图

 JVM内存结构是java必须掌握的基础

程序技术器

  • 程序技术器,可以看作当前线程所执行字节码的行号指示器
  • 线程私有

JAVA虚拟机栈

  • 线程私有的,生命周期和线程相同
  • 每个方法被执行时创建一个栈帧,用于存储局部变量表(包括参数),操作数栈,动态链接,方法出口等信息
  • 局部变量表存放各种基本数据变量类型boolean,byte,char,short等

本地方法栈

  • 与虚拟机栈基本类似,区别在于虚拟机栈是在虚拟机执行java方法服务,而本地发放栈则是Native发放服务。

Java堆

  • java堆是java虚拟机管理内存中最大的内存区域,也是被各线程共享的一块内存区域,在JVM启动时创建
  • 其大小通过-Xms和-Xmx参数设置,-Xms为JVM启动时申请的最小内存,-Xmx为JVM可申请的最大内存。

发法区

  • 用于存储虚拟机加载的类信息,常量,静态变量,是各个线程共享的内存区域

2.堆的默认分配图

  • Java堆=老年代+新年代
  • 新生代=Eden+s0+s1
  • 新生代和老年代默认比例的值为1:2

3.方法区

 方法区是各个线程共享的内存区域,用来存储已经被虚拟机加载后的类信息,常量,静态变量,还有即时编译后的代码缓存

4.对象的内存布局图

 一个Java对象在堆内存中包括对象头,实例数据和不起填充

  • 对象头包括Mark Word(存储哈希码,GC分代年龄等)和类型指针(对象指向它的类型元数据指针),如果是一个数据对象,还有一个保存数组长度的空间
  • 实例数据是对象存储的有效信息,包括了对象的所有成员变量,大小由各个成员变量大小决定
  • 对齐填充不是必然存在,仅仅起到占位作用

5.对象头的Mark Word图

 Mark Word 用于存储对象自身的运行时的数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等。

6.对象与Monitor关联结构图

 一个java对象在堆中存储一个Java对象在堆内存中包括对象头,对象头有Mark word,Mark word存储着锁状态,锁指针指向monitor地址。这其实是synchronized底层实现的

7.java Monitor工作原理

  •  想要获取monitor的线程,首先会进入Entry_List队列
  • 当某个线程获取对象的monitor后,进入owner区域,设置为当前线程,同时计数器count加1
  • 如果线程调用了wait()方法,则会进入_WaitSet队列。它会释放monitor锁,即将owner赋值为null,count自减1,进入WaitSet队列阻塞等待
  • 如果其他线程调用notify和notifyAll,会唤醒waitSet中的某个线程,该线程再次尝试获取monitors锁,成功进入Owner区域
  • 同步方法执行完毕了,线程退出临界区,会将monitor的owner设为null,并且释放监视锁

8.创建一个对象内存分配流程图

  • 对象一般是在Eden区生成
  • 如果Eden区满了,就会触发Young Gc
  • 触发Young Gc的时候,Eden区实现清除,没有被引用啊的对象直接被删除
  •  依然存活的对象,会被送到suivivor区域,Survivor=s0+s1
  • 每次Young Gc时,存活的对象复制到未使用的那块suivivor区,当前正在使用的另一块Survivor区完全清除,接着交换两块Survivor区的使用状态
  • 如果Young Gc 要移送的对象大于Survivor区上限,对象直接进入老年代
  • 一个对象不能一直呆在新年代,如果它经过多次GC,依然活着,次数超过阈值,直接进入老年代

9.可达性分析算法判断对象存活

 算法的思想:

  • 同一系列称为”GC ROOTS“的对象作为起始点,从这些街道开始根据引用关系向下搜索,搜索走过的路径称为”引用链“,当一个对象到GC Roots 没有任何的引用链,证明此对象不可能被使用

    10.标记-清除算法示意图

  • 标记-清除算法是最基础的垃圾收集算法。
  • 算法分为两个阶段,标记和清除。
  • 首先标记出需要回收的对象,标记完成后,统一回收掉被标记的对象。
  • 当然可以反过来,先标记存活的对象,统一回收未被标记的对象。
  • 标记-清除 两个缺点是,执行效率不稳定和内存空间的碎片化问题~

11.标记-复制算法示意图

  • 1969年 Fenichel提出“半区复制”,将内存容量划分对等两块,每次只使用一块。当这一块内存用完,将还存活的对象复制到另外一块,然后把已使用过的内存空间一次清理掉~
  • 1989年,Andrew Appel提出“Appel式回收”,把新生代划分为较大的Eden和两块较小的Survivor空间。每次分配内存只使用Eden和其中一块Survivor空间。发生垃圾收集时,将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor空间上。Eden和Survivor比例是8:1~
  • “半区复制”缺点是浪费可用空间,并且,如果对象存活率高的话,复制次数就会变多,效率也会降低。

12.标记-整理算法示意图

  • 1974年,Edward 提出“标记-整理”算法,标记过程跟“标记-清除”算法一样,接着让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存~
  • 标记-清除算法和标记整理算法本质差异是:前者是一种非移动式的回收算法,后者是移动式的回收算法。
  • 是否移动存活对象都存在优缺点,移动虽然内存回收复杂,但是从程序吞吐量来看,更划算;不移动时内存分配更复杂,但是垃圾收集的停顿时间会更短,所以看收集器取舍问题~
  • Parallel Scavenge收集器是基于标记-整理算法的,因为关注吞吐。CMS收集器是基于标记-清除算法的,因为它关注的是延迟。

13.垃圾收集器组合图

  • 新生代收集器:Serial、ParNew、Parallel Scavenge
  • 老年代收集器:CMS、Serial Old、Parallel Old
  • 混合收集器:G1

14.类的生存周期

 一个类从被加载到虚拟机内存开始,到卸载出内存为止。

加载阶段:

  • 通过一个类的权限定名来获取二进制字节流
  • 将字节流所代表的静态存储结构转化为方法区运行时数据结构
  • 在内存中生成一个代表这类的java.lang.class对象,作为方法区这个类的各种数据访问入口

验证:

  • 确保Class字节流中包含的信息满足约束要求,保证这些代码在运行时不会危害虚拟机自身安全
  • 验证阶段有:文件格式,元数据,字节码,符号引用校验

准备:

  • 正式为类中定义变量分配内存并设置初始值的阶段

解析:

  • 解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程

初始化:

  • 真正执行列中的字节码

15.栈帧概念结构图

栈帧是用于支持虚拟机进行方法调用和方法执行背后的数据结构。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址信息。

局部变量表

  • 是一组变量值的存储空间,用于存放方法参数和方法内部定义的局部变量。
  • 局部变量表的容量以变量槽(Variable Slot)为最小单位。

操作数栈

  • 操作数栈,也称操作栈,是一个后入先出栈。
  • 当一个方法刚刚开始执行的时候, 该方法的操作数栈也是空的, 在方法的执行过程中, 会有各种字节码指令往操作数栈中写入和提取内容, 也就是出栈与入栈操作。

动态连接

  • 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用, 持有引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。

方法返回地址

  • 当一个方法开始执行时, 只有两种方式退出这个方法 。一种是执行引擎遇到任意一个方法返回的字节码指令。另外一种退出方式是在方法执行过程中遇到了异常。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值