精华内容
下载资源
问答
  • JVM对象创建过程

    2019-10-09 15:32:59
    总所周知,在一个对象被创建之前,必须要进行初始化,所有类加载过程是在对象创建过程之前完成的。 即如果我们用new来创建一个对象,如果类还未被加载的话,会先加载该类,再进行对象的创建。 为对象在堆上分配内存...

    上一节我们讨论了jvm的类加载过程,这一节我们学习一下对象的创建过程。

    判断对象是否初始化,执行类加载
    总所周知,在一个对象被创建之前,必须要进行初始化,所有类加载过程是在对象创建过程之前完成的。
    即如果我们用new来创建一个对象,如果类还未被加载的话,会先加载该类,再进行对象的创建。

    为对象在堆上分配内存。

    分配内存主要有两种方式,指针碰撞和空闲列表。这个主要取决虚拟机的gc是否具有压缩整理的功能

    指针碰撞:假如内存空间是完整的,在空闲内存和已用内存中间有一个内存指针,当分配新的对象内存时,指针向空闲内存区移动新对象内存大小的距离
    空闲列表:当内存空间不是完整的,所有空闲内存保存在列表里,当新对象分配内存时,在空闲列表选取合适的内存大小,然后更新空闲列表信息。

    防止并发
    在虚拟机上创建对象是非常频繁的事,所以可能出现并发问题。jvm提供两种方式来防止并发

    1 堆内存分配空间实现同步处理,jvm通过cas和失败重试来保证更新操作的原子性。
    2 把内存分配的动作按照线程来划分为不同的空间,一开始为每个线程提供堆中的一小块内存,称为线程分配缓冲区tlab,当tlab用完时需要分配新的tlab时才进行同步锁定。

    初始化对象的内存空间
    内存分配完成后,jvm将分配到的内存空间都初始化为零值。

    对象头的设置
    将对象的类,hash码,及分代年龄放入对象头中

    执行java的init方法
    在jvm角度看。设置对象头完成后,对象创建完了,但是在java程序来看,必须执行完init方法和构造函数后才算创建完。

    对象的内存布局
    对象的内存自己是如何布局的呢,主要分为三部分

    • 对象头:
      对象头分为两部分,第一部分存储自身运行时数据,如哈希码,gc分代年龄,锁状态标志,线程持有锁,
      偏向时间戳,偏向时间Id
      第二部分是类型指针,对象指向类元数据的指针,确定是哪个类对象。
    • 实例数据:保存对象中各类型的字段内容
    • 对齐填充:当实例数据部分没有对齐,会进行对齐补全。

    对象的访问定位
    java通过栈上的引用类型reference数据来访问堆中的对象,主要的两种方式是通过句柄访问和直接指针。

    使用句柄:
    如果采用句柄访问,堆中会划分一段区域作为句柄区,而reference则保存句柄的地址,句柄保存对象的实例数据与类型数据各自的地址。
    在这里插入图片描述
    直接指针:
    栈中的referrence直接指向存储对象实例数据的地址。对象实例数据中包含对象类型数据的指针。
    在这里插入图片描述
    hotspot使用的是指针对象访问

    展开全文
  • JVM 对象创建过程

    2020-09-04 14:21:31
    对象创建流程步骤包括哪些 虚拟机遇到一条new指令时,首先检查这个对应的类能否在常量池中定位到一个类的符号引用 判断这个类是否已被加载、解析和初始化 为这个新生对象在Java堆中分配内存空间 Java堆分配...

    对象创建的流程步骤包括哪些

    对象创建底层的顺序.png

    • 虚拟机遇到一条new指令时,首先检查这个对应的类能否在常量池中定位到一个类的符号引用
    • 判断这个类是否已被加载、解析和初始化
    • 为这个新生对象在Java堆中分配内存空间

    Java堆分配内存空间的方式主要有以下两种

    对象分配.png

    指针碰撞

    • 分配内存空间包括开辟一块内存和移动指针两个步骤
    • 非原子步骤可能出现并发问题,Java虚拟机采用CAS配上失败重试的方式保证更新操作的原子性

    空闲列表

    • 分配内存空间包括开辟一块内存和修改空闲列表两个步骤
    • 非原子步骤可能出现并发问题,Java虚拟机采用CAS配上失败重试的方式保证更新操作的原子性
    • 将分配到的内存空间都初始化为零值

    • 设置对象头相关数据

    • GC分代年龄
    • 对象的哈希码 hashCode
    • 元数据信息
    • 执行对象<init>方法

     

    对象的数据结构

    对象内存布局.png

    • 对象头
      1)对象头用于存储对象的元数据信息,包括对象运行时数据和类型指针
      2)Mark Word 部分数据的长度在32位和64位虚拟机(未开启压缩指针)中分别为32bit64bit,存储对象自身的运行时数据如哈希值等。Mark Word一般被设计为非固定的数据结构,以便存储更多的数据信息和复用自己的存储空间
      3)类型指针:指向它的类元数据的指针,用于判断对象属于哪个类的实例

    • 实例数据存储的是真正有效数据,如各种字段内容,各字段的分配策略为longs/doubles、ints、shorts/chars、bytes/boolean、oops(ordinary object pointers),相同宽度的字段总是被分配到一起,便于之后取数据。父类定义的变量会出现在子类定义的变量的前面

    • 对齐填充部分仅仅起到占位符的作用

    对象访问的定位方式

    当我们在堆上创建一个对象实例后,就要通过虚拟机栈中的reference类型数据来操作堆上的对象

    现在主流访问方式有两种(HotSpot虚拟机采用的是第二种

    1. 使用句柄访问对象。即reference中存储的是对象句柄的地址,而句柄中包含了对象实例数据与类型数据的具体地址信息,相当于二级指针

    对象句柄访问.png

    2.直接指针访问对象。即reference中存储的就是对象地址,相当于一级指针

    直接指针访问对象.png

    对比

    垃圾回收方式分析

    方式1当垃圾回收移动对象时,reference中存储的地址是稳定的地址,不需要修改,仅需要修改对象句柄的地址;
    方式2垃圾回收时需要修改reference中存储的地址

    访问效率分析

    方式2优于方式1,因为方式2只进行了一次指针定位,节省了时间开销,而这也是HotSpot采用的实现方式

    展开全文
  • JVM对象创建流程解析

    2018-10-19 11:48:44
    jvm创建对象的第二步就是划分这块空间的,划分空间还有讲究,有两种方式,第一种是如果java堆是连续分配的,那么我们在已经分配给实例对象的堆空间和还在空着未分配给实例对象的堆空间之间有一个分界线,我们用指针...
    Person p = new Person();
    

    这是一个简单的创建对象语句,让我们来看看java虚拟机是如何实现它的:

    1.类加载检查

    jvm遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过,如果没有则进行相应的类加载过程。

    2.jvm分配内存

    java程序在运行时,虚拟机会在内存中申请一块内存空间用来运行jvm:

    在这里插入图片描述

    在这块jvm内存区域中,有两块区域,堆和栈,如图:
    在这里插入图片描述
    我们写的类,如Person这个类,类的名字,有什么成员变量什么成员方法等信息,都保存在栈中输入Person类的区域,相当于一个类的模板,如图:
    在这里插入图片描述
    而我们真正通过Person p = new Person();去new一个类的时候,也就是实例化这个类的时候,实例对象存储的空间是在堆中,只不过我们在栈中存储了这个实例对象的名字还有一些别的信息,但是等到去拿这个对象所存储的数据等东西的时候,还是要去堆中寻找:
    在这里插入图片描述
    jvm创建对象的第二步就是划分这块空间的,划分空间还有讲究,有两种方式,第一种是如果java堆是连续分配的,那么我们在已经分配给实例对象的堆空间和还在空着未分配给实例对象的堆空间之间有一个分界线,我们用指针来指向这个位置,如图:
    在这里插入图片描述
    当我们下一次创建对象在堆空间中为它分配空间的时候,直接将指针向未利用的空间移动出这个新对象的大小就可以了,如图:
    在这里插入图片描述
    这种方式叫做“指针碰撞

    另一种方式就比较好理解了,jvm使用一个列表来记录已利用的堆空间和未利用的堆空间,每次给新对象分配堆空间的时候,都会更新列表中的记录,这种方式叫做“空闲列表

    3.设置对象基本信息

    对象分配到空间之后,JVM会将分配到的内存空间都初始化为零值(不包括对象头),虚拟机要对对象进行必要的基本信息设置。如该对象是哪个类的实例、如果找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头中,被叫做“Mark Word”,这一部分信息存放在我们刚才所说的栈中用来存放实例对象信息的空间中。

    4.初始化对象和调用构造函数

    直到这一步,我们才真正按照代码编写者的意愿,对对象进行初始化操作,如:对对象中的成员变量赋初值,调用构造函数等操作,到次位置一个对象才算是完成了创建和初始化的操作,可以使用了。

    展开全文
  • 一.jvm对象创建 对象在类加载之后创建,主要存储在堆中,也有可能通过逃逸分析存储在栈中。以下是对象加载流程图。 1.检查类加载 首先在new关键词、对象克隆、对象初始化时,jvm会去检查该对象对应的类对象是否...

    一.jvm对象的创建
    首先说明下,new一个子类,在创建时,子类和父类调用顺序:
    父类静态块>子类静态块> 父类属性(先系统默认值,后直接你赋予的值) >父类构造器>子类属性>子类构造器
    对象在类加载之后创建,主要存储在堆中,也有可能通过逃逸分析存储在栈中。以下是对象加载流程图。
    在这里插入图片描述
    1.检查类加载
    首先在new关键词、对象克隆、对象初始化时,jvm会去检查该对象对应的类对象是否已经被加载。具体操作是在常量池找到对应类的符号引用,检查这个类是否被加载、验证、准备、解析、初始化过、
    2.分配内存
    内存分配主要采用两种方式:
    (1)指针碰撞(默认方式)
    如果java堆中内存是绝对规整的,所有用过的内存放一边,未使用过的放一边,中间有一个指针作为临界点,如果新创建了一个对象则是把指针往未分配的内存挪动与对象内存大小的相同距离
    (2)空闲列表
    如果java堆中的内存空间不是规整的,就会维护一个空闲列表,用来记录剩余可用的空间,为对象分配内存时,就在空闲列表中取出大于当前对象大小的空间划分给对象
    出现的问题
    在并发的情况下,有可能同时有两个以上的对象申请。针对这种情况jvm采用了一下两种方式
    (1)cas同步机制
    (2)本地线程分配缓存(TALB):为每个线程在堆上预分配一块私有空间
    3.初始化
    将分配到的内存空间都初始化为0值,保证对象的实例字段不赋初始值也能使用,即直接使用0值
    4.设置对象头
    对象在内存中存储的布局可以分为3块区域:对象头(Header)、 实例数据(Instance Data)和对齐填充(Padding)。
    在这里插入图片描述
    对象头分为Mark Word、Klass Word。
    Mark Word::这里面主要包含对象的哈希值、年龄分代、锁标志位等
    Klass Word::类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
    5.执行init方法
    就是为属性赋值(注意,这与上面的赋0值不同,这是由程序员赋的值),和执行构造方法

    二.内存分配机制

    一.堆的分配机制
    空间分为新生代和老年代。新生代又分为eden区(伊甸园),Survivor1和Survivor2区。
    新生代和老年代的比例为1:2,Eden与Survivor区默认比例为8:1:1。
    1.JVM会试图为Java对象在Eden中初始化一块内存区域;
    2.当Eden空间不够时,JVM产生一次minor gc,通过可达性分析,释放在Eden中的垃圾,释放后把存活的数据放入空的Survivor区。
    3.当Eden空间再次不够是,JVM有产生一次minor gc,把Eden和Survivor中的垃圾回收,把存活的数据放入另一个空的Survivor区中。
    4.每次minor gc,survivor的存活对象年龄+1,当survivor中的对象到达一定年龄后,存入老年区域。
    5.当老年代内存空间不足时,产生full gc
    二.大对象提前进入老年区
    JVM参数 -XX:PretenureSizeThreshold 可以设置大
    对象的大小,如果对象超过设置大小会直接进入老年代,不会进入年轻代,避免大对象的赋值操作,影响效率。
    三.逃逸分析
    jvm中存在逃逸分析,分析当前方法栈帧中的对象是否会在别的栈帧中引用,如果没有,会采用标量替换的方式,优先分配在栈上(栈上分配)。
    测试代码

    package com.company.gc;
    
    import com.company.clone.Student;
    
    import java.io.IOException;
    
    public class AllotOnStack {
        public static void main(String[] args) throws IOException, InterruptedException {
            long start = System.currentTimeMillis();
            for (int i = 0; i < 5000000; i++) {
                alloc();
            }
            long end = System.currentTimeMillis();
            System.out.println(end - start);
            Thread.sleep(1000000);
        }
    
        private static void alloc() {
            Student user = new Student();
            user.setSex(12);
            user.setName("zhuge");
        }
    }
    

    VM options:-Xmx12m -Xms12m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:+EliminateAllocations
    以上为开启逃逸分析设置,执行代码结果。
    启动代码,首先通过jps指令获取当前线程的id 13104
    在这里插入图片描述

    通过jamp -histo 13104指令,获取堆中对象的信息
    在这里插入图片描述
    在这里插入图片描述
    当前对象在堆中的个数只有67179,也就是说大部分的对象都创建在了栈上。

    展开全文
  • 一、对象创建过程 首先我们通过一张图与一段代码来大概了解创建一个对象的步骤。 New类名 。》图中为New String(),指定创建的对象为String 根据new的参数在常景池中定位一个类符号的引用。》图中创建了String...
  • 对象创建过程 class loading 加载class到内存汇总 class linking verification 校验是否语句满足JVM规范 preparation 初始化提供默认值 resolution class解析 class initializing 提供初始值 申请对象内存 ...
  • JVM对象创建

    2021-04-07 10:49:08
    图示对象创建主要流程 分配内存 处理并发安全问题 对象的访问定位 Java程序需要通过 JVM 栈上的引用访问堆中的具体对象。对象的访问方式取决于 JVM 虚拟机的实现。目前主流的访问方式有 句柄 和 直接指针 两种...
  • JVM对象创建流程

    千次阅读 2017-12-21 19:32:37
    java是一门面向对象的编程语言,在java程序运行过程中无时无刻都有对象创建出来。在语言层面上,创建对象(例如克隆,反序列化)通常仅仅是一个new关键字而已,而在虚拟机中,对象(限于普通java对象,不包
  • jvm对象创建过程

    千次阅读 2014-04-30 10:04:05
    2虚拟机为新生对象分配内存,分配方式有指针碰撞,空闲列表.(这里对象创建是非常频繁的,需要考虑原子性问题)3内存分配后,jvm要将分配到的内存初始化为零值。4jvm对象进行必要的设置,入对象是哪个类的,对象的...
  • JVM创建对象过程

    2019-07-21 14:56:26
    JVM创建对象过程如下:
  • JVM(二)JVM 创建对象过程分析

    千次阅读 2018-01-19 11:15:11
    首先来看一下JVM创建对象时的流程图: Created with Raphaël 2.1.2开始JVM 执行 new 指令类已加载?为新生对象分配内存内存规整?指针碰撞并发处理:同步或TLAB将分配到的内存空间初始化为零值JVM
  • jvm对象创建过程

    2021-02-08 23:57:47
    1.1 对象创建过程图解 1.2 对象创建过程说明 二、对象的栈上分配 三、对象在堆中分配 一、jvm中对象的创建过程 1.1 对象创建过程图解 1.2 对象创建过程说明 类加载检查。当java虚拟机遇到一个...
  • JVM创建对象过程简介

    2018-12-13 17:23:26
     Java程序运行时无时无刻都有对象创建出来,在语言层面上,创建对象只是通过一个new关键字,那么在JVM对象是如何被创建出来的? JVM解析到new指令时,会去常量池中(方法区里面)定位该类的符号引用,并且检查...
  • JVM-对象创建过程

    2020-03-05 21:13:04
  • JVM——对象创建过程

    千次阅读 2018-03-23 20:11:51
    对象的创建过程:我们在Java代码中new 一个对象时,我们很难看到对象创建的过程,尤其是在jvm内存中的过程,下面来介绍一下对象创建jvm中的过程: 对象实例在jvm中是存在于java堆中的,每一个对象实例都会占用...
  • 一、对象创建过程 二、对象的内部结构(内存分配) 1、对象头 hashcode GC分代年龄 线程编号 锁编号 时间戳 引用计数 … 2、实例数据   存储所定义的各种类型字段内容,无论是从父类继承下来,还是在子类中...
  • JVM对象创建过程

    2017-06-23 23:22:02
    在这个创建对象过程中,JVM做了不少的工作,流程大体如下: Created with Raphaël 2.1.2Startnew 指令定位类引用,是否被加载?分配内存并初始化零值按java代码进行初始化End执行类加载yesno 定位符号引用 ...
  • java对象创建底层执行图 创建对象流程 1、虚拟机遇到一个new指令时,首先检查这个对应的类能否在常量池中定位到一个类的符号引用。 2、判断这个类是否已被加载、解析和初始化。 3、为这个新生对象在java堆中...
  • <p>title: 一张图秒懂JVM中的对象创建过程 tags: <li>JVM abbrlink: 9f80d882 date: 2020-11-29 20:07:55
  • JVM 如何创建Java对象

    千次阅读 2015-08-04 20:38:02
    在Java程序中,创建一个对象通常需要一个new关键字就够了,但是在虚拟机中,这个过程却有点复杂,这里面包括了类加载、内存分配、初始化零值等等一系列的步骤。 下面来看看JVM如何创建一个对象(这里面的对象仅仅...
  • 下图便是 Java 对象创建过程,我建议最好是能默写出来,并且要掌握每一步在做什么。 Java创建对象过程 1. 类加载检查: 虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个...
  • java是一门面向对象的编程语言,在程序运行过程中无时无刻都有对象创建。对于语言层面来说,创建对象通过new关键字就可以实现,但在JVM层面上伴随着以下的复杂过程
  • JVM 创建 Java 对象

    2019-06-25 10:53:25
    JVM 创建 Java 对象流程:类的加载,内存分配、对对象进行必要的设置、执行 <init> 方法初始化。 1.JVM 创建 Java 对象 使用 new 关键字可以创建一个类的对象。 new指令在虚拟机中的执行操作: 类的...
  • JVM对象创建与内存分配机制--JVM系列(3)

    万次阅读 热门讨论 2020-11-12 10:52:38
    前言:学习本章前先阅读之前我写的关于JVM系列的前两篇文章: JVM类加载机制深入浅出分析 -- JVM系列(1) JVM内存模型 -- JVM系列(2)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 238,728
精华内容 95,491
关键字:

jvm对象创建过程