第二章:Hotspot虚拟机对象

  • 对象创建

虚拟机遇到一个new指令时,首先去,检查这个指令的参数是否在常量池中定位到一个雷的符号引用,并且检查这个符号引用代表的雷是否已被加载、解析、初始化过。

在类加载检查通过后,虚拟机将会为新对象分配内存,对象所需要的内存大小在加载后可以确定,为对象分配内存的任务就是把一块确定大小的内存从Java堆中划分出来。

  • 假如堆时绝对规整的,所有用过的内存放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那么分配内存就仅仅是把那个指针指向空闲空间的那边挪动一段和对象大小相等的距离。这种分配内存的方式叫做指针碰撞(Bump the Pointer)
  • 如果java堆并不是规整的,已使用的内存和空间内存相互交错,那就没办法简单的通过指针碰撞分配内存了,虚拟机必须维护一个表,记录哪些内存块是可用的,在分配内存时从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种方式叫做空闲类别free list。

具体选择哪种分配内存方式与GC有关,如果GC支持压缩,那么可以使用指针碰撞,否则就只能使用空闲列表了。使用Serial、ParNew等代用压缩过程的收集器时,系统采用指针碰撞,而使用CMS这种基于Mark-sweep算法的收集器时,通常采用空闲指针的方式。

除了如何划分可用内存之外,还有另一个需要考虑的问题时对象创建的是否频繁,因为堆内存时所有线程共享的,如果分配内存空间太频繁,会有竞争问题,虚拟机为了解决这个问题,使用了CAS配上失败重试的方式保证更新操作时原子性的。

另一种解决冲突的方式是把内存分配的动作按照线程划分在不同的空间中进行,即每个线程在Java堆上预先分配一块内存,这种方式成为Thread Local Allocation Buffer。

内存分配完毕后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),如果是TLAB方式,则初始化提前至TLAB分配时进行。这一步骤保证了对象的实例字段在Java代码中可以不赋初值就直接使用,程序访问这些字段的数据字段对应的零值。

  • 对象内存布局

在Hotspot虚拟机中,对象在内存中存储的布局可以分为三部分:对象头、实例数据、对齐填充。

  • 对象头用于存储两部分信息:第一部分用于存储对象自身的运行时数据,例如哈希吗、GC分代年龄、锁状态标识、线性持有的锁、偏向线程ID、偏向时间戳等,这部分可以成为Mark Word。
  • 对象头的另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象时哪个类的实例。并不是所有的虚拟机实现都必须在对象数据上保留类型指针,即查找对象的元数据信息并不一定要经过对象本身,如果一个对象是Java数组,那么对象头中还必须有一块记录数组长度的数据,因为虚拟机可以通过普通的Java对象的元数据中确定Java对象的大小,但是从数组的元数据中无法确定数组的大小。
  • 实例数据部分数据是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论从父类继承来的还是在子类中定义的,都需要记录起来。
  • 第三部分对齐填充:并不是必然的,它仅仅起到占位符的作用,由于Hotspot虚拟机的自动内存管理系统要求对象起始位置地址必须是8字节的整数倍,因此如果对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

对象的访问定位

reference类型在Java虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,所以对象访问方式取决于虚拟机实现。主流的定位对象实例方式有两种:使用句柄和直接指针方式。

  • 使用句柄的话,会在Java堆中分配一块内存作为句柄池,而句柄中包含了对象的实例数据和类型数据各自的具体地址信息。
  • 如果使用直接指针的方式,会在Java堆中存储对象实例的同时存储指向方法区的类型数据。

两种方式各有优势:使用句柄来访问的最大好处是referrence中存储的是稳定的句柄信息,在对象被移动时,只会改变句柄中的实例数据指针,而reference本身不会修改。

使用直接指针访问方式的最大好处就是速度快,它节省了一次指针定位的时间开销,对于对象的访问在Java中非常频繁,因此这类开销积少成多后会造成很客观的成本。

原文地址:https://www.cnblogs.com/use-D/p/10612052.html

时间: 2024-11-05 17:31:57

第二章:Hotspot虚拟机对象的相关文章

【深入理解JAVA虚拟机】第二部分.内存自动管理机制.2.HotSpot虚拟机对象探秘

2.HotSpot虚拟机对象探秘 对象的创建过程 1.加载类 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载. 解析和初始化过. 如果没有,那必须先执行相应的类加载过程. 2.分配内存 在类加载检查通过后,接下来虚拟机将为新生对象分配内存. 对象所需内存的大小在类加载完成后便可完全确定为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来. 分配方式: 1.指针碰撞.适用于连续内存,需要垃圾回收

HotSpot虚拟机对象相关内容

一.对象的创建 1.类加载检查 普通对象的创建过程:虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那么必须先执行相应的类加载过程. 2.分配内存 分配内存时主要注意两个问题:1.如何分配空间.2.修改指针时如何实现线程安全. 如果内存是规整的,就使用"指针碰撞"的方式,即将空闲部分的指针移动对象内存大小相等的距离.如果内存不是规整的,虚拟机必须维护一个表,记录那些内存块可

深入理解JVM:HotSpot虚拟机对象探秘

对象的创建 java是一门面向对象的语言.在Java程序执行过程中无时无刻有Java对象被创建出来.在语言层面上,创建对象(克隆.反序列化)一般是一个newkeyword而已,而在虚拟机中,对象的创建步骤例如以下: 1.当虚拟机遇到new指令时.首先将去检查这个指令參数能否在常量池中定位到一个类的引用符号,而且检查这个符号引用代表的类是否被载入.解析和初始化过.假设没有.那必须先执行相应的类载入过程. 2.在类载入检查通过以后.接下来虚拟机将为新生对象分配内存.对象所需的内存大小在类载入后便确定

HotSpot虚拟机对象探秘

一.对象的创建: 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载,解析和初始化过.如果没有,那必须先执行响应的类加载过程.对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来. 对象空间分配方式:指针碰撞, 空闲列表 创建的步骤: 1.检查是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有必须

《深入理解Java虚拟机》笔记 第二章 Java虚拟机内存区域

? ? 这句话感觉道出了GC的本质 ? ? ? ? ? ? 1.程序计数器(Program Counter Register) ? ? 程序计数器是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器.字节码解释器工作时就是通过改为这个计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等基础功能都需要依赖这个计数器来完成. ? ? 由于Java虚拟机的多线程是通过线程轮流切换CPU时间片的方式来实现的,所以在任何一个时刻,一个处理器(对于多核处理

JAVA 入门第二章 (面对对象)

本渣渣鸽了一个月终于有时间更新.因为有c++基础,学起来这章还是比较简单的,本章我觉得是程序猿质变课程,理解面向对象的思想,掌握面向对象的基本原则以及 Java 面向对象编程基本实现原理,熟练使用封装.继承.多态面向对象三大特性,感受和c++之间的异同,下面是学习路线. 1.类和对象  1-1 什么是类和对象 1-2 如何定义 Java 中的类 1-3 如何使用 Java 中的对象 1-4 Java 中的成员变量和局部变量 1-5 Java 中的构造方法 1-6 Java 中的 static 使

Thinking in Java(第四版)—— 第二章 一切皆对象

一.对象保存的位置 寄存器(cpu) 栈(变量) 堆(对象) 静态域(static) 常量池(string) 非内存区池 二.基本数据类型 整数型 byte short int long 8 16 32 64 浮点型 float double 32 64 字符型 char 16 Unicode 布尔型 boolean 1 三.static 属于类调用不属于对象(一般工具类中用的多)

第二章--应用程序对象

上下文对象HttpContext 为了进一步简化服务器端对参数的处理工作,ASP.NET中定义了HttpContext类型来统一处理参数的表示问题 底层方法: RewritePath 将服务器收到的请求URL替换为另一个指定的URL (可以做地址的映射) GetSection 获取配置文件中的配置节 RemapHandler 重新设置当前的处理程序应用程序对象 HttpApplication 当HttpContext对象创建之后,HttpRuntime将随后创建一个用于处理请求的对象,这个对象的

第二章 便利的对象

像数组.散列(就是哈希)这样保存对象的对象,我们称为容器. 索引:我们最常见的数组下标就是索引. (1) (2) (3) (4) (5)正则表达式 /模式/=~希望匹配的字符串 nil是什么? nil表示对象不存在,就像在正则表达式中表示无法匹配成功一样,方法不能返回有意义的值时就会返回nil.从数组或散列中获取对象时若指定的索引或者键不存在也是返回nil.