深入理解Java虚拟机(二)——HotSpot对象创建、内存、访问
对象的创建
虚拟机遇到一条字节码new指令时,开始对象创建过程。
- 首先去检查这个指令的参数是否能在常量池定位到一个类的符号引用;
- 检查这个符号引用代表的类是否已被加载、解析和初始化,如果没有就必须执行相应的类加载过程;
- 根据方法区中该类的信息确定对象的所需空间大小;
- 虚拟机为新生对象分配内存;
- 将对象实例的内存(不包括对象头)进行初始化为零值;
- 配置对象头的信息;
- 调用对象的构造函数进行初始化。
这样,一个真正可用的对象被完全构造出来了。
多线程中,引用指向对象的内存空间和对象初始化操作可能会出现重排序,这样会导致对象没有初始化就被其他线程使用了,就会出错。方法这种情况,就需要将对象声明为volatile。《Java并发编程艺术》
分配内存方法
虚拟机为新生对象分配内存有两种方法:
- 碰撞指针:如果虚拟机垃圾收集器采用的复制算法或者标记-整理算法,那么堆中空闲内存和已使用过的内存是连续放在一块的,二者中间存在一个指针作为分界点的指示器。这样分配内存的时候,只需要将指针向空间区域挪动一段与对象大小相同的距离,这种方式就是指针碰撞。
- 空闲列表 :如果虚拟机垃圾收集器采用的标记-清除算法:那么堆中的空闲内存和已使用内存不是连续的,是交错的,虚拟机通过维护一张列表来记录可用内存块,在分配内存的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表,这种分配方式就是空闲列表。
所以,虚拟机采用何种内存分配方法,取决于其所用的垃圾回收算法。
并发时对象分配
解决并发时对象分配的问题:即使仅仅修改一个指针所指向的位置,在并发情况下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。
两种方案可以解决:
- 通过CAS配上失败重试的方法可以保证操作的原子性。
- 通过给每个线程一个本地线程分配缓冲区,当线程需要分配内存时,就在它相应的缓冲区分配,当缓冲区耗尽,就进行同步锁定。
对象的内存模型
对象在堆内存中可以划分为三个部分:
- 对象头
- 实例数据
- 对齐补充
1.对象头
对象头包括两类信息:
- 第一类用于存储对象自身的运行时数据:例如哈希码、GC分代年龄、锁状态、线程持有的锁、偏向线程ID、偏向时间戳等。
- 可能还存在第二类是类型指针,就是对象指向它的类型元数据指针,虚拟机通过这个指针来确定该对象是哪个类的实例。
- 如果是Java数组对象,对象头重还必须有一块数据用于记录数组的长度。
2.实例数据
是对象真正存储的有效信息,就是在程序代码里面定义的给中类型的字段内容,成员变量的值,其中包含父类的成员变量和当前类定义的变量。
3.对齐填充
作用只是占位符。并不是必然存在的。
HotSpot要求对象的起始地址必须是8子节的整数倍,所以任何对象的大小都必须是8子节的整数倍。对象头已经被设计为8字节的整数倍,如果实例数据没有对齐,就需要通过对齐填充部分进行补全。
对象访问定位
Java程序会通过栈上的reference数据来操作堆上的具体对象。所谓reference类型就是一个指向对象的引用。
主流的访问方式有两种:
- 使用句柄访问:
堆中划分出一块内存作为句柄池,用于存放对象实例数据和类型数据各自的地址信息。Java栈中存放的引用指向句柄池中对象的句柄地址。 - 直接指针访问:
引用类型指向的是对象的地址,不需要句柄池直接访问对象。但是对象的内存中就需要放置访问类型数据的相关地址信息。
比较:
- 句柄访问的好处是句柄地址稳定,当对象被垃圾收集器移动时,只会改变句柄池中的实例数据地址,而本地变量表中的引用不需要被修改。
- 直接指针访问的好处就是速度快,节省指针定位的时间开销。HotSpot主要采用这种方式进行访问。


深入理解Java虚拟机(二)——HotSpot对象创建、内存、访问的更多相关文章
- 深入理解Java虚拟机二:垃圾收集与内存分配
垃圾收集:垃圾收集要完成三件事,包括哪些内存需要回收,什么时候回收及如何回收. 1.需要回收的内存判定:没有引用指向原先分配给某个对象的内存时,则该内存是需要回收的垃圾 Java垃圾收集器在对内存进行 ...
- 深入理解Java虚拟机二 阅读笔记
xl_echo编辑整理.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!! --- > 以下内容摘抄自 ...
- 深入理解Java虚拟机:垃圾收集器与内存分配策略
目录 3.2 对象已死吗 判断一个对象是否可被回收 引用类型 finalize() 回收方法区 3.3. 垃圾收集算法 1.Mark-Sweep(标记-清除)算法 2.Copying(复制)算法 3. ...
- 《深入理解Java虚拟机》学习笔记之内存分配
JVM在执行Java程序的过程中会把它所管理的内存划分若干个不同的数据区域,如下图: 大致可以分为两类:线程私有区域和线程共享区域. 线程私有区域 程序计数器(Program Counter Regi ...
- 《深入理解java虚拟机》读书笔记1--java内存区域
Java内存管理 本文主要介绍Java虚拟机运行时的内存区域是如何划分的.Java对象的创建过程.Java对象的内存布局.Java对象的访问定位 一:运行时区域划分 主要可以分为以下 几个: 程序计数 ...
- java虚拟机(三)--HotSpot 对象
普通对象的创建(不包括数组和class对象): 当虚拟机遇到new指令时,会在常量池中检查是否包含这个类的符号引用(全限定名),通过这个确定是否经过类加载的过程,如果true,为该 对象分配内存,对象 ...
- 深入理解Java虚拟机(四)——HotSpot垃圾收集器详解
垃圾收集器 新生代收集器 1.Serial收集器 特点: 单线程工作,收集的时候就会停止其他所有工作线程,用户不可知不可控,会使得用户界面出现停顿. 简单高效,是所有收集器中额外内存消耗最少的. 没有 ...
- 深入理解Java虚拟机二之Java内存区域与内存溢出异常
运行时数据区域 1.线程独有的内存区域 PROGRAM COUNTER REGISTER 程序计数器 程序计数器空间较小,是当前线程执行字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值 ...
- 深入理解Java虚拟机笔记——垃圾收集器与内存分配策略
目录 判断对象是否死亡 引用计数器算法 可达性分析算法 各种引用 回收方法区 垃圾收集算法 标记-清除算法 复制算法 标记-整理算法 分代收集算法 HotSpot算法实现 枚举根节点 GC停顿(Sto ...
随机推荐
- 在Service中创建全局Dialog对话框
需要使用到悬浮窗权限 val builder: AlertDialog.Builder = AlertDialog.Builder(this)builder.setMessage("from ...
- istio in kubernetes (一) --原理篇
背景 微服务是什么 • 服务之间有轻量级的通讯机制,通常为REST API • 去中心化的管理机制 • 每个服务可以使用不同的编程语言实现,使用不同的数据存储技术 • 应用按业务拆分成服务,一个大型应 ...
- flink1.10版本StreamGraph生成过程分析
1.StreamGraph本质 本质就是按照用程序代码的执行顺序构建出来的用于向执行环境传输的流式图,并且可以支持可视化展示给用户的一种数据结构. 2.StreamGraph.StreamNode和S ...
- 一个List按照某个size分割为多个小的List
针对于List的size比较大,使用多线程处理任务时,可以将List分割为一个一个比较小的任务单元进行处理. 例如集合大小:645,按照100分割,会将集合分割为6个size为100的集合和一个siz ...
- 微信支付回调 敏感信息解密 v3 php
今天博主用了一波微信的v3版本的支付,支付成功后发现回调跟v2的完全不一样,于是去看了了一波v3的文档,发现信息是经过加密的,需要解密才能获取的到 但是最悲催的是文档上没写怎么解密的,经过了一下午的百 ...
- 面试阿里,美团,京东都会被问到的Spring ,从基础到源码帮你全搞定
1 前言 Spring是一个轻量级开源框架,它是为了解决企业应用开发的复杂性而创建的.框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框 ...
- UIWebView各种加载网页的方式
UIWebView加载网页的方法 最近在使用UIWebView的时候遇到各种不同形式加载网页的方式,总结起来共有三种方式,分别为:使用URL加载,使用HTML源码加载,使用HTML文件加载,各种方法的 ...
- LeetCode周赛#207
5519. 重新排列单词间的空格 #字符串 #模拟 题目链接 题意 给定字符串text,该字符串由若干被空格包围的单词组成,也就说两个单词之间至少存在一个空格.现要你重新排列空格,使每对相邻单词间空格 ...
- lambda表达式中无法抛出受检异常!
抛出受检异常的时候,我们的接口应该带上throw关键字,但通过lambda表达式实现的Consumer的accept方法并不带有关键字,因此在lambda表达式中不能抛出受检异常必须把它吃掉
- Mybatis学习-初步认知与使用
Mybatis是一款优秀的持久层框架.且支持定制化SQL,存储过程以及高级映射 Mybatis几乎免除了所有的JDBC代码以及设置参数和获取结果集的工作,它使用简单的XML或注解来配置原始类型.接口和 ...