JVM对象创建详解

JVM对象创建是指的java程序使用new操作符或者反射调用newInstance方法实例化对象时在JVM内存区域创建对象的过程,分配了对象的内存空间之后,JVM会给实例变量赋予初始化值,简要的图例如下:

简单来说整个过程就是对象创建会首先在Eden区进行内存分配,创建完成之后栈空间中的变量会对其进行引用。但是实际上整个过程远没有描述这么简单,下面来具体分析一下对象的创建过程。

首先创建的对象需要在Eden区分配内存空间,如果此时堆区的空间是完全规整的且连续的,那么创建的新对象就直接按照顺序分配到指定的位置上,然后通过指针移动就可以指向下一个新的未分配的位置,这种方式成为“指针碰撞”。但是如果堆区空间不连续,这个时候分配的新对象内存也是不连续的,这个时候就没有能力只通过指针移动指向来实现对象的内存空间分配,而必须开辟一个新的空间用于缓存当前整个堆区中未使用过的内存地址列表,通过这个列表来找到未分配的内存地址,这种方式成为“空闲空间”。是采用“指针碰撞”还是采用“空闲空间”是根据当前JVM堆空间的结构来进行的。以下图示阐述了两种方式创建对象时内存分配情况:

指针碰撞:

空间空间:

创建对象的并发问题:

上述两个过程为java对象在JVM内存结构中的详细创建过程,但是java程序天生就是多线程,所以对于创建对象来说会存在竞争(内存分配竞争),如果两个线程同时创建对象分配内存空间,就会出现相同的内存空间资源成为互相竞争的资源。JVM遇到这种情况有两种解决办法,一种的会采用CAS(compare and set)的方式进行内存的分配。另外一种称为TLAB(Thread Local Allocation Buffer)来解决竞争,这种方式是为每一个线程创建一个对应的堆空间,让分配内存的操作下放到TLAB中进行。

对象在堆区中的数据结构:

对象在堆区中主要有两部分组成,一部分是对象的头,一部分是实例数据。

对象的头包含了例如GC分代年龄, 对象的hash值,偏向锁的线程ID,轻量级和重量级锁(monitor)的指针等,这个部分也称为mark word,除此之外还有另外一个部分,这个部分是这个对象的类的指针,用于JVM知晓当前实例具体来自于哪一个类。

实例数据包括了对象真正存储的信息,包含本身字段的内容,从父类继承下来的内容等等,具体这里就不再详述。

对象的访问规则:

所谓的对象访问规则实际上指的是虚拟机栈中的本地变量如何引用对象实例的过程(如何通过引用找到实例本身),有两种方式可以实现,句柄池和直接引用。

句柄池:

在栈空间中并不直接获取指向堆区中对象实例的指针,而是通过在堆区中维护一个句柄池,通过句柄池的指针再指向最终实例对象,这种方式的好处在于栈空间的指针并不会随着对象的位置变动而发生变化,因为句柄池已经把这个变化给屏蔽掉了。

直接引用:

顾名思义就是没有维护中间引用而是直接在栈空间通过指针直接指向对象实例。

句柄池和直接引用这两种方式各有优劣,直接引用更加迅速,只有一次指针定位的开销,而句柄池更加稳定,对象被移动(垃圾回收)后也能够保证指针不变。

总结:对象的创建过程就是分配内存空间,赋予实例变量初始值并且建立与栈区变量的指针引用关系(通常来说这个关系应为GC Roots)

时间: 2024-08-15 17:36:38

JVM对象创建详解的相关文章

Qt on Android: Qt Quick 组件与对象动态创建详解

在<Qt on Android: Qt Quick 事件处理之信号与槽>一文中介绍自定义信号时,举了一个简单的例子,定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Connections 对象连接到组件的 colorPicked 信号,改变文本的颜色. 当时用到的 Component . Loader 两个特性,一直没来得及介绍,可能很多人都还在雾里看花呢.这次呢,我们就来仔仔细细地把他们讲清楚. 请给我的参赛文章<Qt on Androi

Python:file/file-like对象方法详解【单个文件读写】

IO中读写文件操作方法汇总!----The_Third_Wave的学习笔记! 本文由@The_Third_Wave(Blog地址:http://blog.csdn.net/zhanh1218)原创.不定期更新,有错误请指正. Sina微博关注:@The_Third_Wave 如果这篇博文对您有帮助,为了好的网络环境,不建议转载,建议收藏!如果您一定要转载,请带上后缀和本文地址. class file(object) |  file(name[, mode[, buffering]]) -> fi

010-Scala单例对象、伴生对象实战详解

010-Scala单例对象.伴生对象实战详解 Scala单例对象详解 函数的最后一行是返回值 子项目 Scala伴生对象代码实战 object对象的私有成员可以直接被class伴生类访问,但是不可以被其他的类或者对象访问 伴生类访问伴生对象的成员时,要通过名称.成员来访问 调用一些元素的方法初始化创建的时候,例如:Array(1,2,,34,5,6)其实调用了它的apply()方法 欢迎广大爱好者学习交流.也欢迎广大学习爱好者加入 DT大数据梦工厂交流群:462923555 DT大数据微信公众账

关于Defferred对象知识详解

关于Defferred对象知识详解 一.什么是deferred对象 Deferred是jQuery开发团队为延时操作做出的回调函数的解决方案,意思是延时到某个时间点再执行. 二.deferred的实现 1.创建三个$.Callbacks对象,分别表示成功done,失败fail,处理中process三种状态 2.对应了三种处理结果,resolve(已完成).rejiect(以失败).notify(未完成) 3.创建一个promise对象,具有state.always.then.primise方法

JavaScript对象类型详解

JavaScript对象类型详解 JavaScrtip有六种数据类型,一种复杂的数据类型(引用类型),即Object对象类型,还有五种简单的数据类型(原始类型):Number.String.Boolean.Undefined和Null.其中,最核心的类型就是对象类型了.同时要注意,简单类型都是不可变的,而对象类型是可变的. 什么是对象 一个对象是一组简单数据类型(有时是引用数据类型)的无序列表,被存储为一系列的名-值对(name-value pairs).这个列表中的每一项被称为 属性(如果是函

JVM类加载机制详解(二)类加载器与双亲委派模型

在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可以通过jar包.war包.网络中获取.JSP文件生成等方式. 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构.这里只是转化了数据结构,并未合并数据.(方法区就是用来存放已被加载的类信息,常量,静态变量,编译后的代码的运行时内存区域) 3.在内存中生成一个代表这个类的java.lan

kubernetes资源创建详解【持续完善中】

目录 资源创建详解 一:Pod及常用参数 1.简介 2.模板 3.删除pod 4.设置Pod主机名 5.镜像拉取策略(ImagePullPolicy) 二:RC 1.简介 2.模板 三:Deployment 1.简介 2.模板 四:HPA 1.简介 2.模板 五:StatefulSet 1.简介 2.模板 六:PV和PVC 八:扩展 8.1.Pod调度到指定的Node 资源创建详解 一:Pod及常用参数 1.简介 2.模板 3.删除pod 示例流程如下: 用户发送删除pod的命令,默认宽限期是3

JVM之GCRoots详解

JVM之GCRoots详解目录面试题引子什么是垃圾判断对象是否可以被回收之引用计数法判断对象是否可以被回收之枚举根节点可达性分析Java中可以作为GC Roots的对象1. 面试题引子一面:GC Roots如何确定?哪些对象可以作为GC Roots?2. 什么是垃圾1.简单说就是内存中已经不再被使用到的空间就是垃圾 3. 判断对象是否可以被回收之引用计数法Java中,引用和对象是有关联的.如果要操作对象则必须用引用进行.因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收.简单说,

笔记-【3】-event事件对象的详解!

event事件对象:是指当前对象发生的事件的一些详细的信息在event这个对象里. event对象从哪里来?从事件函数中传入 obj. //e就会当前的事件对象event } 对象就有属性和方法:那么event对象也有属性和方法 event的属性和方法: { 属性: button :  当前事件的方法中判断鼠标的按键位置 有三个值: 0 (左键) 1(滚轮) 2(右键) ctrlkey:  判断是否按下了ctrl键; altkey:  判断是否按下了alt键; shiftkey:  判断是否按下