一文了解JVM(中)
HotSpot 虚拟机对象探秘
对象的创建
| Header | 解释 |
|---|---|
| 使用 new 关键字 | 调用了构造函数 |
| 使用 Class 的 newInstance 方法 | 调用了构造函数 |
| 使用 Constructor 类的newInstance 方法 | 调用了构造函数 |
| 使用 clone 方法 | 没有调用构造函数 |
| 使用反序列化 | 没有调用构造函数 |
说到对象的创建,首先让我们看看 Java 中提供的几种对象创建方式:
下面是对象创建的主要流程:

虚拟机遇到一条 new 指令时,先检查常量池是否已经加载相应的类,如果没有,必须先执行相
应的类加载。类加载通过后,接下来分配内存。若 Java 堆中内存是绝对规整的,使用“指针碰
撞“方式分配内存;如果不是规整的,就从空闲列表中分配,叫做”空闲列表“方式。划分内存
时还需要考虑一个问题--并发,也有两种方式: CAS 同步处理,或者本地线程分配缓冲(Thread
LocalAllocation Buffer, TLAB)。然后内存空间初始化操作,接着是做一些必要的对象设置(元信
息、哈希码…),最后执行 <init> 方法。
为对象分配内存
类加载完成后,接着会在 Java 堆中划分一块内存分配给对象。内存分配根据Java 堆是否规整,
有两种方式:
指针碰撞:如果 Java 堆的内存是规整,即所有用过的内存放在一边,而空闲的的放在另一
边。分配内存时将位于中间的指针指示器向空闲的内存移动一段与对象大小相等的距离,这
样便完成分配内存工作。
空闲列表:如果 Java 堆的内存不是规整的,则需要由虚拟机维护一个列表来记录那些内存
是可用的,这样在分配的时候可以从列表中查询到足够大的内存分配给对象,并在分配后更
新列表记录。
选择哪种分配方式是由 Java 堆是否规整来决定的,而 Java 堆是否规整又由所采用的垃圾收集器
是否带有压缩整理功能决定。

处理并发安全问题
对象的创建在虚拟机中是一个非常频繁的行为,哪怕只是修改一个指针所指向的位置,在并发情
况下也是不安全的,可能出现正在给对象 A 分配内存,指针还没来得及修改,对象 B 又同时使
用了原来的指针来分配内存的情况。解决这个问题有两种方案:
对分配内存空间的动作进行同步处理(采用 CAS + 失败重试来保障更新操作的原子性);
把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java 堆中预先分配
一小块内存,称为本地线程分配缓冲(Thread LocalAllocation Buffer, TLAB)。哪个线程
要分配内存,就在哪个线程的 TLAB 上分配。只有 TLAB 用完并分配新的 TLAB 时,才需要
同步锁。通过-XX:+/-UserTLAB 参数来设定虚拟机是否使用 TLAB。

对象的访问定位
Java 程序需要通过 JVM 栈上的引用访问堆中的具体对象。对象的访问方式取决于 JVM 虚拟机
的实现。目前主流的访问方式有** 句柄** 和 直接指针 两种方式。
指针: 指向对象,代表一个对象在内存中的起始地址。
句柄: 可以理解为指向指针的指针,维护着对象的指针。句柄不直接指向对象,而是指向
对象的指针(句柄不发生变化,指向固定内存地址),再由对象的指针指向对象的真实内存
地址。
句柄访问
Java 堆中划分出一块内存来作为句柄池,引用中存储对象的句柄地址,而句柄中包含了对象实例数据与对象类型数据各自的具体地址信息,具体构造如下图所示:

优势:引用中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍
的行为)时只会改变句柄中的实例数据指针,而引用本身不需要修改。
直接指针
如果使用直接指针访问,引用 中存储的直接就是对象地址,那么 Java 堆对象内部的布局中就必
须考虑如何放置访问类型数据的相关信息。

优势:速度更快,节省了一次指针定位的时间开销。由于对象的访问在 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.model 或 os.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** 中内存泄露
的发生场景。
什么情况下会发生栈内存溢出
栈是线程私有的,他的生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用
来存储局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表又包含基本数据类
型,对象引用类型.
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError 异常,
方法递归调用产生这种结果。
如果 Java 虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是无法申请到足够的内
存去完成扩展,或者在新建立线程的时候没有足够的内存去创建对应的虚拟机栈,那么
Java 虚拟机将抛出一个 OutOfMemory 异常。(线程启动过多)
参数 -Xss 去调整 JVM 栈的大小
一文了解JVM(中)的更多相关文章
- 重磅硬核 | 一文聊透对象在 JVM 中的内存布局,以及内存对齐和压缩指针的原理及应用
欢迎关注公众号:bin的技术小屋 大家好,我是bin,又到了每周我们见面的时刻了,我的公众号在1月10号那天发布了第一篇文章<从内核角度看IO模型的演变>,在这篇文章中我们通过图解的方式以 ...
- JVM中的STW和CMS
Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外).Java中一种全局暂停现象,全局停顿,所有Java代码停 ...
- 一文学会JVM性能优化
实战性能优化 1 重新认知JVM 之前我们画过一张图,是从Class文件到类装载器,再到运行时数据区的过程,现在咱们把这张图不妨丰富完善一下,展示了JVM的大体物理结构图. 执行引擎:用于执行JVM字 ...
- 数据库(一):事务的特性与事务(在同一个 JVM 中)的传递
参考文章 https://blog.csdn.net/shuaihj/article/details/14163713 https://blog.csdn.net/shfqbluestone/arti ...
- JVM中的动态语言支持简介
抽丝剥茧 细说架构那些事——[优锐课] 从版本6开始,JVM已扩展为支持现代动态语言(也称为脚本语言).Java8的发行为这一领域提供了更多动力.感到这种支持的必要性是因为Java作为一种语言固有地是 ...
- 一文洞悉JVM内存管理机制
前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 学习导图: 一.为什么要学习内存管理? Java与C++之间有一堵由内存动态分配和垃圾回收机制所围成的高墙,墙 ...
- JVM中对象模型及相应名词概念
JVM中对象模型及相应名词概念 java对象在jvm中的模型是OOP-Klass 模型: klass klass对应元数据,包括常量池.字段.方法等.是在加载class阶段创建instanceKlas ...
- SharePoint 2013 文档库中PPT转换PDF
通过使用 PowerPoint Automation Services,可以从 PowerPoint 二进制文件格式 (.ppt) 和 PowerPoint Open XML 文件格式 (.pptx) ...
- 【转】JVM运行原理及JVM中的Stack和Heap的实现过程
来自: http://blog.csdn.net//u011067360/article/details/46047521 Java语言写的源程序通过Java编译器,编译成与平台无关的‘字节码程序’( ...
- jvm中的年轻代 老年代 持久代 gc
虚拟机中的共划分为三个代:年轻代(Young Generation).老年代(Old Generation)和持久代(Permanent Generation).其中持久代主要存放的是Java类的类信 ...
随机推荐
- 很强!4.7k star,推荐一款Python工具,可实现自动化操作!!
1.介绍 在日常工作中,肯定会遇到一些重复性的工作,不管是点击某个按钮.写东西,打印东西,还是复制粘贴拷贝资料之类的,需要进行大量的重复操作.按键精灵大家都听说过,传统的方式,大家可以使用按键精灵将操 ...
- vuex合作怎么用仓库
- win10更新后使用ie浏览器自动跳转edge的解决方法
win10更新后使用ie浏览器自动跳转edge的解决方法 ①在系统的搜索框中搜索internet选项 ②打开界面中,选择高级的栏位 ③然后在红框的地方找到启用第三方浏览器扩展,去掉勾选 ④应用,确定, ...
- 力扣326(java)-3的幂(简单)
题目: 给定一个整数,写一个函数来判断它是否是 3 的幂次方.如果是,返回 true :否则,返回 false . 整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3x 示例 1: 输 ...
- 优化搜索排序结果从而“ 提升CTR、CVR业务指标”
简介: 搭建搜索功能不难,难的是如何提高搜索质量,帮助用户快速找到心中所想的内容或商品,那么搜索结果的相关性排序则是影响用户体验最关键的一环,本文通过阿里云开放搜索电商行业解决方案和大家聊一聊如何优化 ...
- OpenKruise v1.0:云原生应用自动化达到新的高峰
简介:OpenKruise 是针对 Kubernetes 的增强能力套件,聚焦于云原生应用的部署.升级.运维.稳定性防护等领域. 云原生应用自动化管理套件.CNCF Sandbox 项目 -- Op ...
- 当设计模式遇上 Hooks
简介: 数据结构与设计模式能够指导我们在开发复杂系统中寻得一条清晰的道路,既然都说 Hooks 难以维护,那就尝试让「神」来拯救这混乱的局面.对于「设计模式是否有助于我们写出更优雅的 Hooks 」 ...
- 7.prometheus监控--监控docker
4.监控docker 为了能够获取到Docker容器的运行状态,用户可以通过Docker的stats命令获取到当前主机上运行容器的统计信息,可以查看容器的CPU利用率.内存使用量.网络IO总量以及磁盘 ...
- Istio微服务入门---通过istio部署微服务实现灰度发布(15)
一.Istio简介 1.1 Istio介绍 官方文档:https://istio.io/docs/concepts/what-is-istio/ 中文官方文档:https://istio.io/zh/ ...
- ESP32 SNTP校时
一.连接WIFI 在进行时间同步之前,先连接WIFI #include "wifi.h" #include <string.h> #include <stdlib ...