关于jvm:爆肝整理JVM十大模块知识点总结不信你还不懂

50次阅读

共计 3130 个字符,预计需要花费 8 分钟才能阅读完成。

01 JVM 内存构造

Java 虚拟机的内存空间分为 5 个局部:

  • 程序计数器
  • Java 虚拟机栈
  • 本地办法栈
  • 办法区

JDK 1.8 同 JDK 1.7 比,最大的差异就是:元数据区取代了永恒代。元空间的实质和永恒 代相似,都是对 JVM 标准中办法区的实现。不过元空间与永恒代之间最大的区别在于:元数据空间并不在虚拟机中,而是应用本地内存。

1.1 程序计数器(PC 寄存器)

(1)程序计数器的定义 程序计数器是一块较小的内存空间,是以后线程正在执行的那条字节码指令的地 址。若以后线程正在执行的是一个本地办法,那么此时程序计数器为 Undefined。

(2)程序计数器的作用

  • 字节码解释器通过改变程序计数器来顺次读取指令,从而实现代码的流程管制。
  • 在多线程状况下,程序计数器记录的是以后线程执行的地位,从而当线程切换回 来时,就晓得上次线程执行到哪了。

(3)程序计数器的特点  是一块较小的内存空间。

  • 线程公有,每条线程都有本人的程序计数器。
  • 生命周期:随着线程的创立而创立,随着线程的完结而销毁。
  • 是惟一一个不会呈现 OutOfMemoryError 的内存区域。

因为文章篇幅问题,部门内容将以图片展现,如有小伙伴需残缺文档进行查阅观看点赞 + 关注之后【点击此处】即可获取!!

1.2 Java 虚拟机栈(Java 栈)

(1)Java 虚拟机栈的定义 Java 虚拟机栈是形容 Java 办法运行过程的内存模型。

Java 虚拟机栈会为每一个行将运行的 Java 办法创立一块叫做“栈帧”的区域,用于寄存该办法运行过程中的一些信息,如:

  • 局部变量表
  • 操作数栈
  • 动静链接
  • 办法进口信息
  • ……

(2)压栈出栈过程 当办法运行过程中须要创立局部变量时,就将局部变量的值存入栈帧中的部分变 量表中。

Java 虚拟机栈的栈顶的栈帧是以后正在执行的流动栈,也就是以后正在执行的 办法,PC 寄存器也会指向这个地址。只有这个流动的栈帧的本地变量能够被操 作数栈应用,当在这个栈帧中调用另一个办法,与之对应的栈帧又会被创立,新 创立的栈帧压入栈顶,变为以后的流动栈帧。

办法完结后,以后栈帧被移出,栈帧的返回值变成新的流动栈帧中操作数栈的一 个操作数。如果没有返回值,那么新的流动栈帧中操作数栈的操作数没有变动。

因为 Java 虚拟机栈是与线程对应的,数据不是线程共享的,因而不必关怀数据 一致性问题,也不会存在同步锁的问题。

(3)Java 虚拟机栈的特点

  • 局部变量表随着栈帧的创立而创立,它的大小在编译时确定,创立时只需调配事 先规定的大小即可。在办法运行过程中,局部变量表的大小不会产生扭转。
  • Java 虚拟机栈会呈现两种异样:StackOverFlowError 和 OutOfMemoryError。
  • StackOverFlowError 若 Java 虚拟机栈的大小不容许动静扩大,那么当线程请 求栈的深度超过以后 Java 虚拟机栈的最大深度时,抛出 StackOverFlowError 异样。

02 HotSpot 虚拟机对象探秘

2.1 对象的内存布局 在 HotSpot 虚拟机中,对象的内存布局分为以下 3 块区域:

  • 对象头(Header)
  • 实例数据(Instance Data)
  • 对齐填充(Padding)

(1)对象头

对象头记录了对象在运行过程中所须要应用的一些数据:

  • 哈希码
  • GC 分代年龄
  • 锁状态标记
  • 线程持有的锁
  • 偏差线程 ID
  • 偏差工夫戳

对象头可能蕴含类型指针,通过该指针能确定对象属于哪个类。如果对象是一个 数组,那么对象头还会包含数组长度。

(2)实例数据

实例数据局部就是成员变量的值,其中包含父类成员变量和本类成员变量。

(3)对齐填充

用于确保对象的总长度为 8 字节的整数倍。HotSpot VM 的主动内存管理系统要求对象的大小必须是 8 字节的整数倍。而 对象头局部正好是 8 字节的倍数(1 倍或 2 倍),因而,当对象实例数据部 分没有对齐时,就须要通过对齐填充来补全。对齐填充并不是必然存在,也没有特地的含意,它仅仅起着占位符的作用

03 垃圾收集策略与算法

程序计数器、虚拟机栈、本地办法栈随线程而生,也随线程而灭;栈帧随着办法 的开始而入栈,随着办法的完结而出栈。这几个区域的内存调配和回收都具备确 定性,在这几个区域内不须要过多思考回收的问题,因为办法完结或者线程完结 时,内存天然就跟随着回收了。而对于 Java 堆和办法区,咱们只有在程序运行期间能力晓得会创立哪些对象,这部分内存的调配和回收都是动静的,垃圾收集器所关注的正是这部分内存。

3.1 断定对象是否存活

若一个对象不被任何对象或变量援用,那么它就是有效对象,须要被回收。

(1)援用计数法

在对象头保护着一个 counter 计数器,对象被援用一次则计数器 +1;若援用 生效则计数器 -1。当计数器为 0 时,就认为该对象有效了。

援用计数算法的实现简略,断定效率也很高,在大部分状况下它都是一个不错的 算法。然而支流的 Java 虚拟机里没有选用援用计数算法来治理内存,次要是因 为它很难解决对象之间循环援用的问题。

举个栗子对象 objA 和 objB 都有字段 instance,令 objA.instance = objB 并且 objB.instance = objA,因为它们相互援用着对方,导致它们的援用计数 都不为 0,于是援用计数算法无奈告诉 GC 收集器回收它们。

(2)可达性分析法

所有和 GC Roots 间接或间接关联的对象都是无效对象,和 GC Roots 没无关 联的对象就是有效对象。

GC Roots 是指:

  • Java 虚拟机栈(栈帧中的本地变量表)中援用的对象
  • 本地办法栈中援用的对象
  • 办法区中常量援用的对象
  • 办法区中类动态属性援用的对象

GC Roots 并不包含堆中对象所援用的对象,这样就不会有循环援用的问题。

04 HotSpot 垃圾收集器

HotSpot 虚拟机提供了多种垃圾收集器,每种收集器都有各自的特点,尽管我 们要对各个收集器进行比拟,但并非为了挑选出一个最好的收集器。咱们抉择的 只是对具体利用最合适的收集器。

4.1 新生代垃圾收集器

(1)Serial 垃圾收集器(单线程)只开启一条 GC 线程进行垃圾回收,并且在垃圾收集过程中进行所有用户线程 (Stop The World)。

个别客户端利用所需内存较小,不会创立太多对象,而且堆内存不大,因而垃圾 收集器回收工夫短,即便在这段时间进行所有用户线程,也不会感觉显著卡顿。因而 Serial 垃圾收集器适宜客户端应用。

因为 Serial 收集器只应用一条 GC 线程,防止了线程切换的开销,从而简略高 效。

(2)ParNew 垃圾收集器(多线程)

ParNew 是 Serial 的多线程版本。由多条 GC 线程并行地进行垃圾清理。但 清理过程仍然须要 Stop The World。

ParNew 谋求“低进展工夫”, 与 Serial 惟一区别就是应用了多线程进行垃圾收 集,在多 CPU 环境下性能比 Serial 会有肯定水平的晋升;但线程切换须要额 外的开销,因而在单 CPU 环境中体现不如 Serial。

05 内存调配与回收策略

06 JVM 性能调优

在高性能硬件上部署程序,目前次要有两种形式:

  • 通过 64 位 JDK 来应用大内存;
  • 应用若干个 32 位虚拟机建设逻辑集群来利用硬件资源。

07 类文件构造

08 类加载的机会

09 类加载的过程

10 类加载器

10.1 类与类加载器

(1)判断类是否“相等”任意一个类,都由加载它的类加载器和这个类自身一起确立其在 Java 虚拟机中 的唯一性,每一个类加载器,都有一个独立的类名称空间。

因而,比拟两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前 提下才有意义,否则,即便这两个类来源于同一个 Class 文件,被同一个虚构 机加载,只有加载它们的类加载器不同,那么这两个类就必然不相等。这里的“相等”,包含代表类的 Class 对象的 equals() 办法、isInstance() 方 法的返回后果,也包含应用 instanceof 关键字做对象所属关系断定等状况。

正文完
 0