创建对象的过程及对象的访问定位

对象的创建

对象创建的几种方式

一、 用new来创建

二、 克隆

三、 Class对象和Constructor中的newInstance()方法

四、 反序列化

对象创建的过程(不包括数组对象和Class对象的创建)

一、 类加载,如果该对象对应的类还没有被加载到内存中则会就行类的加载,可能会涉及到父类的加载(具体看类的加载过程)

二、 分配内存,当类加载完成后对象所需的内存就可以确定,就可以为其分配内存,在内存分配时有两种方法:

  1、 指针碰撞法:将指针作为已经分配内存和未分配内存的分界线,当给对象分配内存时指针做相应的移动,这种方法要求内存空间是规整的

  2、 空闲列表法:找到一块足够大的空间划分非给对象,并且标记该内存块,这种方法不要求内存规整但是会造成碎片空间,如何在两种方法中进行选择是由堆是否规则决定的,而堆是否规整则又收到垃圾回收器对垃圾回收算法的选择(通常为两种:标记-整理和标记-清除),标记-整理算法会维持堆的规整,而标记-清除则不会

在内存分配时由于并发操作可能存在一些错误,通常解决并发问题的方法有下面两种:

  1、 CAS失败重试

  2、 把内存分配的动作按照线程划分在不同的空间中进行(TLAB:本地线程分配缓冲)

三、 初始化内存为零值,由于这部操作实例变量在未进行初始化就可以使用

四、 设置对象的相关信息,设置对象头中的相关参数,例如对象的哈希码、分代年龄,具体可以看对象的内存布局。

五、 执行init()方法,init方法中是我们在定义类时再类中赋初值的成员的赋值,不包括被static或者final修饰的成员,他们在类加载阶段就被赋值。

对象的内存布局:

对象的内存主要分为三部分:对象头、实例数据、对齐填充

一、对象头:对象头又分为运行时数据、类型指针。哈希码、分代年龄、锁状态标志、线程持有的锁等都属于运行时数据,类型指针用于确定对象属于哪个类的实例。

二、实例数据:存储对象中的信息,例如类中的字段

三、对齐填充:只起到填充作用

对象的访问定位

在使用对象时,我们是通过在栈中创建一个对象的引用,通过对象的引用再找到实际的对象实例,而对象的引用找到实际的对象实例有两种方式:一种是句柄,另一种是直接指针

 

使用句柄:使用句柄时在堆中有分配了一个区域---句柄池,句柄池中包含实例数据指针和对象类型数据指针,再通过这两个指针指向实例数据和对象类型数据,这样的话当堆中发生垃圾回收后导致实例数据的地址改变时只会引起句柄池中实例数据指针的改变,而不会导致栈中对象引用的改变

使用直接指针:使用直接指针后就不需要使用句柄池,对象的引用直接指向对象,这样就减少了实例数据指针指向实例数据这一个过程,所以使用直接指针比使用句柄更加高效,但是当对象的地址改变时对象的引用的值也会改变。

说明:对象的引用变量是在虚拟机栈中分配的,实例数据属于对象内存的一部分,在堆中分配,对象的类型数据其实就是类的相关数据,是在方法区中分配的,在对象的内存布局的时候我们就知道对象的对象头中有一个类型指针,该指针就是指向方法区中的类的,所以使用句柄和直接指针的两种方式这一个指向过程都是不能省略的。

图片引用:https://blog.csdn.net/hbtj_1216/article/details/77599990

原文地址:https://www.cnblogs.com/zhaolei1996/p/10952646.html

时间: 2024-07-30 08:10:36

创建对象的过程及对象的访问定位的相关文章

jvm学习记录-对象的创建、对象的内存布局、对象的访问定位

简述 今天继续写<深入理解java虚拟机>的对象创建的理解.这次和上次隔的时间有些长,是因为有些东西确实不好理解,就查阅各种资料,然后弄明白了才来做记录. (此文中所阐述的内容都是以HotSpot虚拟机为例的.) 对象的创建 java程序在运行过程中无时无刻都有对象被创建出来,那么创建对象是个怎么样的过程呢?还是看看我自己的理解吧. 判断是否已经执行类加载 当虚拟机遇到一条new指令时 ,首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载

Java对象的内存布局以及对象的访问定位

先来看看Java对象在内存中的布局 一 Java对象的内存布局 在HotSpot虚拟机中,对象在内存中的布局分为3个区域 对象头(Header) Mark Word(在32bit和64bit虚拟机上长度分别为32bit和64bit)存储对象自身的运行时数据,包括哈希码,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时 间戳等 类型指针 即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例.但是并不是所有类型虚拟机实现都必须在对象数据上保留类型指针,如果对象是一

读《jvm虚拟机》 - 对象的访问定位

上一篇看了堆内存是怎么创建对象的,那么创建完肯定要使用对象啦~ 那是怎么访问对象呢? java 程序是通过栈上的reference数据来操作堆上的具体对象的. 首先我们回顾一下虚拟机栈: 虚拟机栈是 java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表.操作数栈.动态链接.方法出口等信息. 局部变量表存放了编译期可知的各种基本数据类型(long,boolean,int,byte,short,long,double,float).return

java对象的访问定位方式

java对象在访问的时候,我们需要通过java虚拟机栈的reference类型的数据去操作具体的对象.由于reference类型在java虚拟机规范中只规定了一个对象的引用,并没有定义这个这个引用应该通过那种方式去定位.访问java堆中的具体对象实例,所以一般的访问方式也是取决与java虚拟机的类型.目前主流的访问方式有通过句柄和直接指针两种方式. 1.句柄访问 使用句柄访问方式,java堆将会划分出来一部分内存去来作为句柄池,reference中存储的就是对象的句柄地址.而句柄中则包含对象实例

Java对象的访问定位

java对象在访问的时候,我们需要通过java虚拟机栈的reference类型的数据去操作具体的对象.由于reference类型在java虚拟机规范中只规定了一个对象的引用,并没有定义这个这个引用应该通过那种方式去定位.访问java堆中的具体对象实例,所以一般的访问方式也是取决与java虚拟机的类型.目前主流的访问方式有通过句柄和直接指针两种方式. 1.句柄访问 使用句柄访问方式,java堆将会划分出来一部分内存去来作为句柄池,reference中存储的就是对象的句柄地址.而句柄中则包含对象实例

Java对象创建的过程及对象的内存布局与访问定位

这里以HotSpot为例,且所说的对象指普通的Java对象,不包括数组和Class对象等. 1.对象创建的过程 类加载.解析.初始化:虚拟机遇到new时先检查此指令的参数是否能在常量池中找到类的符号引用,并检查符号引用代表的类是否被加载.解析.初始化,若没有则先进行类加载. 对象内存分配:类加载检查通过后,虚拟机为新生对象分配内存,对象所需内存大小在类加载完成后便可完全确定.分配内存的任务等同于从堆中分出一块确定大小的内存. 根据内存是否规整(即用的放一边,空闲的放另一边,是否如此与所使用的垃圾

【深入理解JVM】:Java对象的创建、内存布局、访问定位

对象的创建 一个简单的创建对象语句Clazz instance = new Clazz();包含的主要过程包括了类加载检查.对象分配内存.并发处理.内存空间初始化.对象设置.执行ini方法等. 主要流程如下: 1. 类加载检查 JVM遇到一条new指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那必须先执行相应的类的加载过程. 2. 对象分配内存 对象所需内存的大小在类加载完成后便完全确定(对象内存布局),

浅谈对象的创建、内存布局和访问定位

在此简单的记录一下<深入理解Java虚拟机>第2章的2.3节内容. 对象的创建 这里的对象的创建是指普通的对象(不包括数组和Class对象).对象的创建简单来说就是执行new的时候,虚拟机做出对应的响应.让我们看看一下虚拟机创建对象的过程: 1.虚拟机遇到new指令时,首先尝试在常量池中定位到对应类的符号引用,并检查这个符号引用代表类是否已被加载.解析和初始化过.如果没有,那必须先执行相应的类加载过程(后续会写一下关于类加载的问题). 2.类加载检查通过后,为新生对象分配内存.对象内存的大小在

java虚拟机学习(二)java对象的创建及访问定位

java对象的创建过程: 对象的创建开始: 虚拟机遇到new 关键字的时候,首先去常量池中寻找有没有这个类的符号引用,并且检查该引用的类是否已经被加载,解析,和初始化过,如果没有则会先执行该类的加载过程, 在通过检查后,虚拟机为该新生对象分配内存. 分配内存: 为对象分配内存有俩种方式: 一种分配方式是"指针碰撞",在内存规整的时候,已使用的内存在一侧,未使用的内存在一侧时,中间为指示器指针,这个时候的内存分配就是把指示器指针向未使用的区域移动至创建的对象大小相等的距离. 另一种分配方