《深入理解JAVA虚拟机(第2版)》—— 学习笔记2

5 篇文章 0 订阅

1、简介

本章主要内容是 运行时数据区、HotSpot虚拟机对象、对象访问定位等。

2、运行时数据区

在这里插入图片描述
通过上图,我们可以看到 运行时数据区 包括:程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区等。

其中,在 程序计数器、Java虚拟机栈、本地方法栈 这三个区域中每个线程有一个专属的区域,线程和线程之间互不干扰,独立存储,这样的内存区域被称为 线程私有 内存。而 Java堆、方法区 是 所有线程共享的内存区域

2.1、程序计数器
  1. 线程私有 的内存
  2. 是一块儿较小的内存空间,Ta 可以看做是当前线程所执行的字节码的行号指示器。白话讲,就是用来记录当前线程执行到哪里了。
  3. 如果线程执行的是一个Java方法,此时程序计数器记录的是正在执行的字节码指令的地址;如果是一个 Native 方法,那记录的就是空(Undefined)。
  4. 该区域是 Java虚拟机规范 中唯一一个没有规定任何 OOM 情况的区域。

这里我们有一个问题:

我们为啥要记录这个?

Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间来实现的。所以,在任何一个时间点上,一个处理器(或者是多核处理器上的一个内核)只会执行一个线程中的字节码指令。假设 T1、T2 两个线程轮流在一个处理器中执行。当 T1 切换到 T2 再由 T2 切换回 T1 的时候,字节码解释器需要知道当时 T1 执行到哪里了,程序计数器此时就派上用场了,因为 Ta 记录了当时 T1 线程当时(T1 切换到 T2 的时候)的状态。

2.2、Java虚拟机栈
  1. 线程私有 的内存
  2. 生命周期与线程一致。
  3. 描述了Java 方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
  4. 在Java虚拟机规范中,此区域可能会出现两种异常:
    – 如果线程请求的栈深度大于虚拟机允许的深度,将抛出 StackOverflowError 异常。
    – 如果虚拟机的栈可以动态扩展,当扩展无法申请到足够的内存,将会抛出 OOM 异常。

我们经常会听到别人说 堆内存(Heap)和 栈内存(Stack)。这里的栈内存(Stack)指的就是 Java 虚拟机栈,再准确点来说,应该是 Java 虚拟机栈中的局部变量表。

2.3、本地方法栈
  1. 线程私有 的内存

  2. 与 Java虚拟机栈 的作用类似。它们之间的区别在于:

    虚拟机栈是为了 虚拟机执行 Java方法(字节码) 而服务的,而本地方法栈是为了 虚拟机执行 Native方法 而服务的。

  3. 虚拟机规范并未对本地方法栈的实现有什么强制规定,各虚拟机可以自由的实现 Ta。甚至像 Sun HotSpot 将虚拟机栈和本地方法栈合二为一

  4. 与虚拟机栈相同,此区域也会抛出 StackOverflowError 和 OOM。

2.4、Java堆
  1. 被所有线程共享的一块儿内存区域。

  2. 该区域是在虚拟机启动的时候创建。

  3. 唯一的目的就是用来存放对象实例,几乎所有对象实例都在这里分配内存。

    这里我们想一个问题:

    是所有的对象实例都会在堆上分配内存吗?

    答案是:并不是。虽然 Java虚拟机规范 中的描述是:所有的对象实例以及数组都要在堆上分配。但随着 JIT编译器 的发展与逃逸分析技术的逐渐成熟,栈上分配标量优化技术 将会导致一些微妙的变化,所有对象都分配在堆上,也变的不那么“绝对”了

  4. Java 虚拟机规范的规定,堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的就行,和磁盘空间一样。

  5. 如果堆中没有内存空间分配给对象实例了,并且也无法再扩展时,将会抛出去 OOM 异常。

2.5、方法区
  1. 被所有线程共享的一块儿内存区域。
  2. 用于存放已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
  3. 在 Java虚拟机规范中,方法区被描述为堆的一个逻辑部分,但 Ta 还有一个别名 Non-Heap(非堆),目的是与Java Heap 区分开来。
  4. Java虚拟机规范的规定,该区域的内存也可以在物理上是不连续的(和 Java Heap 一样)。
  5. 在 Java虚拟机规范 中对该区域的限制非常宽松,甚至该区域可以选择不实现垃圾收集
  6. 当该区域无法满足内存分配的需求时,将会抛出 OOM 异常。

对于 方法区 与 永生代 的关系,大家可以移步到我的另外一篇Blog(JVM HotSpot 之 内存结构演进过程)去进行了解。

2.6、运行时常量池
  1. 该区域在 JDK1.7 中作为方法区的一个组成部分。但是在 JDK1.8 中,该区域被迁移到 堆(Heap)中。
  2. 当类加载后,会将类中的 常量池信息 存放到 运行时常量池 中。
  3. 在 JDK1.7 中,由于该区域属于方法区的一部分,自然就会受到方法区内存的限制,当常量池无法再申请到内存的时候,则会抛出 OOM 异常。
  4. 在 JDK1.8 中,由于该区域属于堆的一部分,自然就会受到堆内存的限制,当常量池无法再申请到内存的时候,则会抛出 OOM 异常。

3、HotSpot 虚拟机对象

  1. 对象的大小在类加载完成的时候就可以确定了。

  2. 为对象分配内存的方式,主要有以下两种

    名称描述
    指针碰撞(Dump the Pointer)如果堆中的内存是 绝对规整的,所有用过的内存都放在一边,空闲的内存放在另外一边,中间放一个指针作为分界点的指示器,分配内存的时候就是把指针向空闲空间的方向移动一段儿与对象大小相等的距离。
    空闲列表(Free List)如果堆中的内存 不是规整 的(已使用的内存和空闲的内存交错),此时虚拟机维护一个列表,用来记录哪些内存块是可用的(空闲的),在给对象分配内存的时候从列表中找到一块儿足够大的空间划分给该对象实例,并更新列表上的记录。
  3. 对象的内存布局,分为三块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Paddding)。对象的大小必须是8字节的整数倍,当 实例数据(Instance Data) 部分没有对齐的时候,就需要 对齐填充(Paddding) 来补全。

3、对象访问定位

Java 程序是通过 中的 reference 数据来操作堆中的具体对象。目前主流有两种方式:句柄 和 指针。

3.1、句柄

在这里插入图片描述
通过上图,我们可以总结以下两点:

  1. 句柄池是在 Java堆 中划出的一个专门区域。
  2. reference 存放的是句柄的地址,而句柄中存放的是对象实例数据和类型数据的具体地址。
3.2、指针

在这里插入图片描述
通过上图,我们可以总结以下两点:

  1. 需要将 对象类型数据的指针 存放在了 对象实例数据 中。
  2. reference 直接存放 对象实例数据的指针
3.3、比较句柄和指针
  1. 句柄最大的好处就是 reference 中存储的是稳定的句柄地址,当对象被移动的时候,只需要改变句柄中的对象实例数指针,栈中的 reference 无需改变。
  2. 比起句柄来说,指针的方式最大的好处就是更快速,因为节省了一次指针定位的时间开销。
  3. Sun HotSpot 采用是指针的方式访问对象。

上一篇:《深入理解JAVA虚拟机(第2版)》—— 学习笔记1
下一篇:《深入理解JAVA虚拟机(第2版)》—— 学习笔记3

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
深入理解Java虚拟(第四)》是一本非常重要的Java虚拟相关的权威书籍,对于深入理解Java虚拟的原理和制具有很大的帮助。 这本书的第四相比之前的本,在内容上进行了全面的更新和拓展。首先,这本书详细介绍了Java虚拟的整体架构和工作原理,包括Java虚拟的类加载、运行时数据区、垃圾回收、即时编译等方面的知识。同时,也对Java内存模型进行了详细的讲解,让读者能够更好地理解Java多线程编程的内存可见性、原子性等问题。 其次,在第四中,作者还新增了对Java虚拟动态编译技术的讲解。这是一项非常重要的技术,能够在运行时动态地将Java字节码编译成本地代码,并进行优化。通过深入了解动态编译技术,读者可以更好地利用Java虚拟的性能,提高程序的运行效率。 最后,这本书还介绍了一些常见的Java虚拟性能调优手段,包括如何通过调整Java虚拟的参数和使用性能分析工具来提高程序性能。这对于开发人员解决实际的性能问题非常有帮助。 总之,《深入理解Java虚拟(第四)》是一本非常权威且全面的Java虚拟相关书籍,通过学习这本书,读者可以深入了解Java虚拟的工作原理和制,并能够运用这些知识来解决实际的性能问题。无论是对于Java开发人员还是对于Java虚拟感兴趣的人来说,这本书都是一本值得阅读的好书。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cab5

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值