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

news2024/9/21 14:28:03

第二章 Java内存区域与内存溢出异常

2.1 概述

JVM是自动内存管理

2.2 运行时数据区

所谓运行时数据区是JVM在运行Java程序的时候将所管理的内存划分为几块不同的数据区域,分为:程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区,如下图:
在这里插入图片描述

2.2.1 程序计数器(Program Counter Register)

  1. 程序计数器可以看作是当前线程所执行字节码指令的行号指示器
  2. 线程私有,每个线程都有一个程序计数器,相互独立,互不干扰。
  3. 如果当前线程正在执行的是一个Java方法,则程序计数器则记录的是字节码指令。如果当前线程正在执行的是Native方法,则程序计数器记录的是空(Undefined)。
  4. 该区域是唯一个一块儿在Java虚拟机规范当中没有规定任何OOM情况的区域
  5. 使用场景
    • 解释执行的时候,要通过程序计数器来获取下一个要执行的字节码指令。
    • Java多线程是通过线程轮流切换并分配处理器执行时间来实现的,当线程切换回来的继续执行的时候,需要恢复到正确的执行位置上。

2.2.2 Java虚拟机栈(Java Virtual Machine Stacks)

  1. 线程私有
  2. 方法在执行的时候会创建一个对应的“栈帧”,用来存放局部变量表、操作数栈、动态链接、方法出口等信息。方法的调用到结束,就是栈帧在Java虚拟机栈中的进栈出栈的过程
  3. 栈帧中的局部变量表
    • 用来存放编译期可知的基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,指向对象的指针或句柄)、returnAddress(一个字节码指令的地址)。
    • 在基本数据类型中的64位长度long和double,需要占用2个局部空间变量(Slot),其他需要占用1个Solt。
    • 局部变量表在编译期间就完成了内存的分配,内存的大小都已确定,运行期也不会有改变。
    • 通常所说的堆内存(Heap),栈内存(Stack)中的栈内存(Stack),指的就是Java虚拟机栈,或者说Java虚拟机栈中的局部变量表部分。
  4. Java虚拟机规范中对该区域规定了2种异常情况
    • 当线程请求的栈深度超过了虚拟机允许的最大深度,则会抛出StackOverflowError异常。
    • 如果虚拟机动态支持扩展,当扩展的时候无法申请到足够的内存,则会抛出OutOfMemoryError异常。

2.2.3 本地方法栈(Native Method Stack)

  1. 如果说Java虚拟机栈是为Java方法服务的,那本地方法栈就是为了Native方法服务的
  2. Java虚拟机规范并没有对本地方法栈如何实现进行规范,各个虚拟机都会有自己具体的实现。例如:HotSpot VM是将本地方法去和Java虚拟机栈合二为一了
  3. Java虚拟机规范对该区域规定了2种异常情况(与Java虚拟机栈一致)。

2.2.4 Java堆(Java Heap)

  1. JVM所管理内存中最大的一块。
  2. 线程共享,所有线程共享这块区域。
  3. Java堆是在JVM启动的时候创建的。
  4. Java堆是用来存放对象实例的,几乎所有对象的内存都是在这里分配的。之所以说几乎,是因为随着JIT的发展和逃逸分析算法的完善,出现了栈上分配、标量替换等优化手段使这个情况发生了一些改变。
  5. Java堆是垃圾收集器所管理的主要区域,因此Java堆又称GC堆
  6. 基于垃圾收集器的分代收集算法,我们又Java堆分为2部分:新生代和老年代,新生代又分为3部分:Eden、From Survivor、To Survivor。
  7. 在线程共享的Java堆中,也会为一些线程分配一块儿线程私有的本地线程分配缓冲区(Thread Local Allocation Buffer,TLAB)
  8. Java虚拟机规范中规定,Java堆可以存在于不连续的物理内存空间上,只要是逻辑上连续就可以。
  9. Java虚拟机规范规定,当此区域无足够的空间来完成实例分配且无法扩展,则抛出OutOfMemoryError异常。

2.2.5 方法区(Method Area)

  1. 该区域线程共享
  2. 用于存放加载后的类、常量、静态变量、编译后的代码
  3. 在Java虚拟机规范中方法区是Java堆的一个逻辑部分,为了与堆区分开,方法区也可叫做非堆(Non-Heap)
  4. 因为方法区是Java堆的一个逻辑部分,则方法区也就和Java堆一样,都是可以存放在物理上不连续的内存空间上,只要逻辑上连续即可。
  5. 垃圾收集器对这个区域主要回收的目标是:卸载的类和对常量池的回收。
  6. Java虚拟机规范中规定,当方法区无法满足内存分配的需求时,则出现OutOfMemoryError异常。
  7. 很多人将“方法区”也称为“永久代”,实际这两者并不等价。只是HotSpot团队将GC分代收集延展到了方法区,或者说用永久代来实现了方法区。这样做的好处是,直接可以复用GC的内存管理,不用再另起炉灶了。其他厂商的虚拟机,例如:JRockit、J9,都没有永久代这个概念。有好处也有不足,带来的问题就是HotSopt相较于其他厂商的虚拟机,更容易出现内存溢出的问题,因为永久代的大小有-XX:MaxPermSize的限制,其他产商的虚拟机是没有这个限制的(只要没有碰触到进程可用内存的上限,就不会出现内存溢出的问题)。在未来的规划当中,HotSpot也是计划要采用Native Memory来实现方法区。

2.2.4 运行时常量池(Runtime Constant Pool)

  1. 作为方法区的一部分
  2. Class文件中有一部分叫做常量池(Constant Pool Table),用来存放编译后产生的各种字面量和符号引用,当类加载完成后,会将这部分信息存放到运行时常量池中。
  3. 比起Class中的常量池,运行时常量池是动态的,即运行期也会产生的一些常量并将这些常量也都存放到运行时常量池中,例如:String的intern()方法。
  4. 作为方法区的一部分,和方法区一样,当无法满足内存分配需求的时候,则出现OutOfMemoryError异常。

2.2.5 直接内存(Direct Memory)

  1. 不属于运行时数据区,也不属于Java虚拟机规范当中规定的内存区域。
  2. NIO(New Input/Output)类,通过该类我们可以使用Native方法直接对堆外内存进行分配,并在堆中生成一个DirectByteBuffer对象作为该内存的引用。
  3. 在设置虚拟机-Xmx参数的时候,如果忽略了直接内存,使得各个内存区域的总和大于了物理内存限制,从而导致动态扩展的时候出现OutOfMemoryError异常。

2.3 HotSpot虚拟机对象探秘

2.3.1 对象的创建

这里以用new命令来创建一个对象为例,说下整个创建过程:

  1. 当碰到new指令的时候,首先检查new指令的参数是否在常量池中有对应的符号引用,如果有的话则检查该符号引用的类是否已经加载、解析、初始化过了。如果没有则先完成类的加载。

  2. 类加载完成后,就要为对象分配内存了,需要多大内存空间在类加载完成后就已经确定了。内存分配的方式有两种:指针碰撞和空闲列表。

    • 指针碰撞:
      如果Java堆是规整的,即已用的内存在一边,空闲的内存在另外一边,两只之间分界点以指针作为指示器。分配内存的时候将指针向空闲空间移动与对象内存大小相等的距离即可。

    • 空闲列表
      如果Java堆不是规整的,那就需要一个列表用来记录空闲的内存空间,分配内存的时候从空闲列表中找到足够大的内存空间分配给对象,并更新空闲列表中的记录。

    使用哪种内存分配方式是由Java堆是否规整来决定的,而Java堆是否规整则是由垃圾收集器是否具备压缩整理功能来决定的。

    创建对象是非常频繁的,我们要考虑并发情况下如何保证分配内存空间线程安全,这里有两个方案:

    • 同步分配内存空间的操作(实际上虚拟机采用的是CAS + 失败重试来实现同步的)
    • 为每个线程在Java堆中分配一块属于该线程的空间,即本地线程分配缓冲区(Thread Local Allocation Buffer,TLAB),线程中的对象将在TLAB上进行分配,如果TLAB不够用了,需要分配新的TLAB的时候,此时才需要同步锁定。
  3. 内存空间分配好后要对内存空间初始化零值。如果使用了TLAB,则该过程提前至TLAB分配的时候进行。

  4. 对对象进行一些必要的设置,例如:它属于哪个类、类的元数据从哪里能找到、对象的Hashcode、对象的GC年龄,这些信息会保存在对象头(Object Head)中,根据当前虚拟机的状态,是否开启偏向锁,对象头会有不同的设置方式。

  5. 以上4步执行完成后,对于虚拟机来说一个对象就算创建完成了,但是对于程序员来说,对象的创建才真正开始(因为init<>方法还没有执行,所有字段都还是零值)。所以,new执行完接着会执行init<>方法,根据程序员的意愿去初始化,至此一个对象才真正的创建完成。

基于以上5个步骤,整理了一个大体的流程图,如下:
在这里插入图片描述

2.3.2 对象的布局

这里所讲的对象内存布局,是基于HotSpotVM来讲的。对象在内存中的布局分为3个部分:对象头,实例数据,对齐填充。

  1. 对象头(Object Head)
    对象头包含两部分信息:一部分对象自身的运行时数据,一部分是对象的类型指针。

    • 对象自身的运行时数据
      这部分数据包括,对象的哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度分别在32位和64位的虚拟机当中为32bit(4字节)和64bit(8字节),官方将这部分数据称为“Mark Word”。
    • 对象的类型指针
      即指向对象的类元数据的指针,虚拟机可以通过这个指针知道这个对象是属于哪个类的实例。
    • 如果对象是数组的话,对象头还需要有一块用来记录数组的长度,因为虚拟机可以通过普通对象的元数据来确定对象的大小,但是无法通过数组的元数据来确定数组的大小。
  2. 实例数据(Instance Data)
    对象真正存储的有效数据,即那些在程序代码中定义的各种类型的字段,无论是从父类继承下来的,还是子类自己定义的。

  3. 对齐填充(Padding)
    HotSpot VM的自动内存管理系统要求对象的大小必须是8字节的整数倍。对象头正好是8字节的倍数(1倍或者2倍),如果实例数据不是8字节的整数倍,就需要对齐填充来进行补全。

2.3.3 对象的访问定位

Java虚拟机规范当中没有对如何对对象进行访问定位有明确的规定,所以要看具体的虚拟机是如何实现的了,主流方式有两种:句柄和指针。

  1. 使用句柄访问
    首先要在Java堆中划出一块区域作为句柄池,虚拟机栈中的reference数据存储的句柄的地址,句柄中会存放对象实例数据的地址和对象类型数据的地址,如下图:
    在这里插入图片描述
    采用句柄的好处是:当对象实例数据的地址发生变化的时候,虚拟机占中的reference数据不需要做任何改变。
  2. 使用指针访问
    虚拟机栈中的reference数据存储的是对象的指针,在对象的对象头中存放该对象的类型数据指针,如下图:
    在这里插入图片描述
    比起使用句柄访问对象,采用指针访问对象的好处是:减少了一次查询的开销,也避免了句柄池占用Java堆的空间。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2082190.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

樊振东代言LV旗下品牌,媒介易解读冠军代言背后的商业逻辑

​近日&#xff0c;法国奢侈品巨头LVMH旗下的德国知名拉杆箱品牌RIMOWA宣布&#xff0c;中国乒乓球奥运冠军樊振东成为其品牌挚友。这一合作不仅是RIMOWA对樊振东在巴黎奥运会上出色表现的认可&#xff0c;也标志着品牌与体育冠军联手打造品牌形象的趋势日益显著。 樊振东&…

Moco求解最优化问题使用教程

理论部分 最简单的例子&#xff0c;流程 输出结果分析 理论部分 moco最终是调用CasAdi求解器来进行求解 对不常见的几个符号表达式含义进行解释&#xff1a; 多刚体动力学公式代表系统中&#xff0c;f_inertial (惯性力和科里奥利力)&#xff1b;f_app (外力和接触力)&…

SQL注入-ctfshow

首先还是对sql的具体分析和讲解 原理&#xff1a; SQL注入是一种安全漏洞&#xff0c;它允许攻击者通过在应用程序的输入中插入或者操作SQL命令来改变后端数据库的查询和操作。SQL注入的主要原因是代码中直接将用户输入与SQL命令拼接在一起&#xff0c;没有进行适当的验证或清…

网络安全可以从事哪些岗位岗位职责是什么网络安全专业的就业前景

网络安全可以从事哪些岗位 伴随着社会的发展&#xff0c;网络安全被列为国家安全战略的一部分&#xff0c;因此越来越多的行业开始迫切需要网安人员&#xff0c;也有不少人转行学习网络安全。那么网络安全可以从事哪些岗位?岗位职责是什么?相信很多人都不太了解&#xff0c;…

『功能项目』着色器光透魔法球Shaders【09】

我们打开上一篇08技能释放的项目&#xff0c; 本章要做的事情是为魔法球增添一个光透效果shaders。 首先在Assets中创建一个Shaders文件夹 接着将场景中的灯光调暗一些&#xff08;避免灯光太强压过将要设置半透明光透效果的魔法球&#xff09; 将新Resources中的Shpere拖拽至…

MQTT服务器-mosquitto配置

我们要使用ESP8266使得STM32能够和服务器之间传递数据&#xff0c;需要有一台MQTT服务器。当然读者可以使用腾讯云、阿里云、OneNet等平台提供的MQTT服务更方便一些。 逻辑是这样的&#xff1a;我们首先需要一台服务器A作为中转站&#xff0c;然后我们的STM32作为客户端能够发…

Java接口中的长连接与短连接详解:概念、应用场景及实现

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

2024年十款好用的图纸加密软件推荐|有效的图纸加密方法分享

在数字化时代&#xff0c;图纸作为企业的重要资产&#xff0c;其安全性显得尤为重要。随着技术的不断进步&#xff0c;市场上涌现出多款优秀的图纸加密软件&#xff0c;为企业和个人提供了强有力的安全保障。本文将为您推荐2024年十款好用的图纸加密软件。 1.安秉图纸加密软件…

JavaSE 面试题 46-50

使用runnable需重写run方法&#xff0c;而且返回值为viod型&#xff0c;等于没有返回值&#xff1b; Thread 类在调用 start()函数后就是执行的 是 Runnable 的 run()函数。 callable需重写call方法&#xff0c;call方法可以有返回值&#xff0c;支持泛型而且可以捕获解决异常&…

秋招突击——知识复习——HTTP/2、HTTP/3的改良

文章目录 引言正文HTTP/1.1与HTTP/1.01、长连接代替短链接2、管道传输缺点 HTTP2.0和HTTP1.11、头部压缩2、二进制格式3、并发传输4、服务器主动推送资源缺点 HTTP/3和HTTP/21、无队头阻塞2、更快的连接建立3、连接迁移 面试题1、HTTP是长连接还是短链接&#xff1f;2、HTTP长连…

中年男明星们,正在视频号“收割”50+姐姐

还记得几年前&#xff0c;抖音上许多大妈和“靳东谈恋爱”的事情吗&#xff1f; 尽管那些靳东高仿号&#xff0c;发的是花花绿绿、粗制滥造的视频&#xff0c;明眼人一看就知真假&#xff0c;但仍有众多大妈痴迷。 如今&#xff0c;在视频号上也有一群姐姐们&#xff0c;“迷恋…

模块化沙箱有几种类型?各类模块化沙箱的功能是什么?

模块化沙箱有几种类型&#xff1f;各类模块化沙箱的功能是什么&#xff1f; 模块化沙箱是一种高灵活性和高扩展性的数据安全产品&#xff0c;通过选择不同的沙箱模块&#xff0c;满足不同的安全需求。 模块化沙箱是SDC沙箱的几种表现形式的总称&#xff0c;模块化沙箱总共分为…

Kubemetes高级调度

一组特殊的容器 初始化容器是用来进行初始化操作的&#xff0c;在很多情况下&#xff0c;程序的启动需要依赖各类配置&#xff0c;资源&#xff0c;但是又不能继承在原有的启动命令或者镜像当中&#xff0c;因为程序的镜像可能并没有加载配置命令&#xff0c;此时InitContaine…

Dubbo ZooKeeper Spring Boot整合

依赖配置 1. Dubbo 起步依赖 Dubbo 是一款高性能的 Java RPC 框架&#xff0c;用于快速开发高性能的服务。 <dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>${dubbo.ver…

Linux中的常见命令——用户管理命令

1、useradd添加新用户 基本语法 语法功能描述useradd 用户名添加新用户useradd -g 组名 用户名添加新用户到某个组 实操案例 1、添加一个新用户【此时的用户是没有密码的】 [rootcentos100 ~]# cd /home [rootcentos100 home]# ls www zss [rootcentos100 home]# useradd…

如果自学通过PMP?

自学&#xff1f;现在没有自学通道啦&#xff0c;要通过有R.E.P授权的机构学习&#xff0c;获得35个PDU才能报考哦~ 所以要报培训班~ 一是&#xff0c;PMP 官方的报考条件需要35个PDU&#xff0c;就是要报机构学习后获得。个人报考渠道去年就关闭了&#xff0c;只能通过机构报…

算法-初阶

文章目录 -1.C 标准0.语法基础 1. C头文件2. C命名空间3. 主函数4. 变量类型5. ASCII码6. 注释1.顺序结构 一、代码示例二、例题1&#xff1a;求圆的面积三、例题2&#xff1a;求解一元二次方程四、总结&#xff1a;2.分支结构 一、代码示例二、例题1&#xff1a;判断一个数是否…

必看 | CDP盘活存量客户的5大步骤和3个应用案例

​“我们有几十家门店&#xff0c;也有APP、小程序和网站&#xff0c;客户信息散落在各系统中&#xff0c;比较杂乱&#xff0c;一直没有统一去维护&#xff0c;现在想把存量客户运营起来&#xff0c;你们CDP能做吗&#xff1f;”类似的咨询&#xff0c;我们几乎每天都会接到。…

工业三防平板全面提升工厂的工作效率

在当今高度自动化和智能化的工业时代&#xff0c;工厂的工作效率成为了企业竞争力的关键因素。而工业三防平板的出现&#xff0c;犹如一颗璀璨的新星&#xff0c;为工厂带来了全新的变革&#xff0c;全面提升了工厂的工作效率。 工业三防平板具备防水、防尘、防摔的特性无论是潮…

基于 Redis 的 HyperLogLog 实现了 UV 的统计

文章目录 前言HyperLogLog 简介HyperLogLog 的工作原理例子总结 前言 在现代网站开发中&#xff0c;用户行为分析是一个非常重要的环节。其中&#xff0c;UV&#xff08;Unique Visitor&#xff0c;独立访客&#xff09;和PV&#xff08;Page View&#xff0c;页面浏览量&…