一文了解JVM(中)

news/2025/3/19 16:00:30/文章来源:https://www.cnblogs.com/xw-01/p/18231964

HotSpot 虚拟机对象探秘

对象的创建

Header 解释
使用 new 关键字 调用了构造函数
使用 Class 的 newInstance 方法 调用了构造函数
使用 Constructor 类的newInstance 方法 调用了构造函数
使用 clone 方法 没有调用构造函数
使用反序列化 没有调用构造函数

说到对象的创建,首先让我们看看 Java 中提供的几种对象创建方式:

下面是对象创建的主要流程:


image


虚拟机遇到一条 new 指令时,先检查常量池是否已经加载相应的类,如果没有,必须先执行相

应的类加载。类加载通过后,接下来分配内存。若 Java 堆中内存是绝对规整的,使用“指针碰

撞“方式分配内存;如果不是规整的,就从空闲列表中分配,叫做”空闲列表“方式。划分内存

时还需要考虑一个问题--并发,也有两种方式: CAS 同步处理,或者本地线程分配缓冲(Thread

LocalAllocation Buffer, TLAB)。然后内存空间初始化操作,接着是做一些必要的对象设置(元信

息、哈希码…),最后执行 <init> 方法。


为对象分配内存


类加载完成后,接着会在 Java 堆中划分一块内存分配给对象。内存分配根据Java 堆是否规整,

有两种方式:

  • 指针碰撞:如果 Java 堆的内存是规整,即所有用过的内存放在一边,而空闲的的放在另一

    边。分配内存时将位于中间的指针指示器向空闲的内存移动一段与对象大小相等的距离,这

    样便完成分配内存工作。

  • 空闲列表:如果 Java 堆的内存不是规整的,则需要由虚拟机维护一个列表来记录那些内存

    是可用的,这样在分配的时候可以从列表中查询到足够大的内存分配给对象,并在分配后更

    新列表记录。


选择哪种分配方式是由 Java 堆是否规整来决定的,而 Java 堆是否规整又由所采用的垃圾收集器

是否带有压缩整理功能决定。


image


处理并发安全问题

对象的创建在虚拟机中是一个非常频繁的行为,哪怕只是修改一个指针所指向的位置,在并发情

况下也是不安全的,可能出现正在给对象 A 分配内存,指针还没来得及修改,对象 B 又同时使

用了原来的指针来分配内存的情况。解决这个问题有两种方案:


  • 对分配内存空间的动作进行同步处理(采用 CAS + 失败重试来保障更新操作的原子性);

  • 把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java 堆中预先分配

    一小块内存,称为本地线程分配缓冲(Thread LocalAllocation Buffer, TLAB)。哪个线程

    要分配内存,就在哪个线程的 TLAB 上分配。只有 TLAB 用完并分配新的 TLAB 时,才需要

    同步锁。通过-XX:+/-UserTLAB 参数来设定虚拟机是否使用 TLAB。


image


对象的访问定位

Java 程序需要通过 JVM 栈上的引用访问堆中的具体对象。对象的访问方式取决于 JVM 虚拟机

的实现。目前主流的访问方式有** 句柄** 和 直接指针 两种方式。



  • 指针: 指向对象,代表一个对象在内存中的起始地址。

  • 句柄: 可以理解为指向指针的指针,维护着对象的指针。句柄不直接指向对象,而是指向

    对象的指针(句柄不发生变化,指向固定内存地址),再由对象的指针指向对象的真实内存

    地址。


句柄访问


Java 堆中划分出一块内存来作为句柄池,引用中存储对象的句柄地址,而句柄中包含了对象实例数据对象类型数据各自的具体地址信息,具体构造如下图所示:


image


优势:引用中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍

的行为)时只会改变句柄中实例数据指针,而引用本身不需要修改。


直接指针

如果使用直接指针访问,引用 中存储的直接就是对象地址,那么 Java 堆对象内部的布局中就必

须考虑如何放置访问类型数据的相关信息。


image


优势:速度更,节省了一次指针定位的时间开销。由于对象的访问在 Java 中非常频繁,因此

这类开销积少成多后也是非常可观的执行成本。 HotSpot 中采用的就是这种方式。


64 位 JVM 中,int 的长度是多数?


Java 中,int 类型变量的长度是一个固定值,与平台无关,都是 32 位。意思就是说,在 32 位

和 64 位 的 Java 虚拟机中,int 类型的长度是相同的。


32 位和 64 位的 JVM,int 类型变量的长度是多数?


32 位和 64 位的 JVM 中,int 类型变量的长度是相同的,都是 32 位或者4 个字节。


怎样通过 Java 程序来判断 JVM 是 32 位 还是 64 位?

你可以检查某些系统属性如 sun.arch.data.modelos.arch 来获取该信息。


32 位 JVM 和 64 位 JVM 的最大堆内存分别是多数?


理论上说上 32 位的 JVM 堆内存可以到达 2^32, 即 4GB,但实际上会比这个小很多。不同操

作系统之间不同,如 Windows 系统大约 1.5GB,Solaris大约 3GB。64 位 JVM 允许指定最大

的堆内存,理论上可以达到 2^64,这是一个非常大的数字,实际上你可以指定堆内存大小到

100GB。甚至有的JVM,如 Azul,堆内存到 1000G 都是可能的。


JRE、JDK、JVM 及 JIT 之间有什么不同?


  • JRE 代表 Java 运行时(Java run-time),是运行 Java 引用所必须的。JDK 代表 Java

    发工具(Java development kit),是 Java 程序的开发工具,如 Java 编译器,它也包含

    JRE。

  • JVM 代表 Java 虚拟机(Java virtual machine),它的责任是运行 Java 应用。

  • JIT 代表即时编译(Just In Time compilation),当代码执行的次数超过一定的阈值时,

    会将 Java 字节码转换为本地代码,如,主要的热点代码会被准换为本地代码,这样有利大

    幅度提高Java 应用的性能。


内存溢出异常

Java 会存在内存泄漏吗?


内存泄漏是指不再被使用的对象或者变量一直被占据在内存中。理论上来说,**Java **是有 GC

垃圾回收机制的,也就是说,不再被使用的对象,会被 GC 自动回收掉,自动从内存中清除。


但是,即使这样,Java 也还是存在着内存泄漏的情况,java 导致内存泄露的原因很明确:长

生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不

再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是** java** 中内存泄露

的发生场景。


什么情况下会发生栈内存溢出

  1. 栈是线程私有的,他的生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用

    存储局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表又包含基本数据类

    型,对象引用类型.

  2. 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError 异常,

    方法递归调用产生这种结果。

  3. 如果 Java 虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是无法申请到足够的内

    存去完成扩展,或者在新建立线程的时候没有足够的内存去创建对应的虚拟机栈,那么

    Java 虚拟机将抛出一个 OutOfMemory 异常。(线程启动过多)

  4. 参数 -Xss 去调整 JVM 栈的大小

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FFT 学习笔记

多项式 复数 单位根 DFT IDFT FFTFFT 学习笔记 1.多项式与卷积 1.1 多项式 对于多项式 \(F(x)=a_0+a_1x+a_2x^2+a_3x^3+\dots+a_nx^n\),我们称 \(a_0,a_1,\dots,a_n\) 为它的系数,这种表示法叫做系数表示法。 定义 \(F(x)\) 的 \(n\) 次项系数为 \(f_n\)。 我们有: \[F(x)=…

题目集4-6的总结性Blog

一.前言: 在这几周,我们又进行了3次pta的题目训练。 首先是答题程序的最后一次迭代,答题程序-4,接着就是新的迭代,家居电路模拟程序。经过一段时间的学习,我对面向对象设计的理解进一步加深,这三次题集写起来也没有之前那么困难了,虽然还有不足,我仍在一次次答题中学…

Kubernetes – 架构

Kubernetes 集群主要由称为节点的工作机器和控制平面组成。集群中至少有一个工作节点。Kubectl CLI 与控制平面通信,控制平面管理工作节点。 Kubernetes – 集群架构 如下图所示,Kubernetes 采用客户端-服务器架构,有主节点和工作节点,主节点安装在单个 Linux 系统上,而节…

九、FreeRTOS学习笔记-列表和列表项

列表和列表项的简介 列表是 FreeRTOS 中的一个数据结构,概念上和链表有点类似,列表被用来跟踪 FreeRTOS中的任务。 列表项就是存放在列表中的项目列表相当于链表,列表项相当于节点,FreeRTOS 中的列表是一个双向环形链表 列表的特点:列表项间的地址非连续的,是人为的连接到…

我真的从测试转成了开发......

写在前面 因为走的圈太大了,早上上班差点迟到,幸好有我每日5公里的加持,侥幸踩点进办公室,哈哈,真的好险! 我开发的功能不能用了 上午开始着手某功能的开发,还在写后台逻辑。 结果到了下午,由于前端同学的代码冲突,打包发布后,导致我写的功能直接不能用了,瞬间emo了…

手把手教你用VM搭建Linux系统

手把手教你用VM搭建Linux系统一、安装vm 查看是否安装成功,打开网络适配器(win+R+ncpa.cpl) 确保有 VMnet1 和 VMnet8二、创建虚拟机step01step02step03 密码123456(我怕我忘了),全名是对你的虚拟机的别称没什么太大作用,用户名代表你说什么用户会涉及到权限step04,位置…

kettle从入门到精通 第六十五课 ETL之kettle 执行动态SQL语句,轻松实现全量增量数据同步

本次课程的逻辑是同步t1表数据到t2表,t1和t2表的表机构相同,都有id,name,createtime三个字段。 CREATE TABLE `t1` (`id` bigint NOT NULL AUTO_INCREMENT,`name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,`createtime` datetime DEFAUL…

HMI-Board之LVGL应用

LVGL应用示例移植 使用默认模板工程新建一个RT-Thread项目,BSP版本为1.1.1打开RT-Thread Settings,点击右侧箭头按钮进入详细页,在硬件栏开启以下几个配置选项(LCD、触摸屏、demo)此时,打开board文件夹,发现下面会有一个lvgl的目录,package目录下会有LVGL和lv-music两个…

升鲜宝牛奶溯源管理系统_2024年全网首发,针对牛奶行业特定的溯源解决方案_一码一物_升鲜宝_余东升_升鲜宝供应链管理系统团队再出新作。

升鲜宝牛奶溯源管理系统_2024年全网首发,针对牛奶行业特定的溯源解决方案_一码一物_升鲜宝_余东升_升鲜宝供应链管理系统团队再出新作。整套软件解决方案分三个端:1.PC后台溯源管理系统2.uniapp溯源小程序员工操作端3.vue3,h5溯源网页展示效果图主要功能:权限管理(组织机构、…

如何设计兜底方案(高可用)

场景: 很多时候,在同步数据时,都会有一个重新推送的按钮,不管是重新推送还是重新拉去。这些动作都是失败后,再次操作,直到成功。这种设计的原因是,程序的运行,不知道什么原因会失败。网络、数据库、服务器,B服务BUG都会导致这段代码执行失败,从而无法保证该功能准确执…

爪哇,我初窥门径

2017年3月,我大二下学期了。 虽说一直在学习,持续在解决学习中遇到的问题,但迷茫依旧。 对着黑框编程,还是不知道Java在现实工作中是用来干什么的。 说实话,真的挺枯燥无趣的。逐渐,我开始意识到,持续搞这些基础,是没有意义的。 我在网上看他们讨论的Java问题,很多我都…