Java是一门面向对象的编程语言,在Java程序运行过程中无时无刻都有对象被创建出来。在语言层面上,创建对象(例如克隆、反序列化)通常仅仅是一个new关键字而已,而在虚拟机中,对象(文中讨论的对象限于普通Java对象,不包括数组和Class对象等)的创建又是怎样一个过程呢

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

在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。

假设Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”(Bump
the Pointer)。

如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”(Free List)。

选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。因此,在使用Serial、ParNew等带Compact过程的收集器时,系统采用的分配算法是指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,通常采用空闲列表。

除如何划分可用空间之外,还有另外一个需要考虑的问题是对象创建在虚拟机中是非常频繁的行为,即使是仅仅修改一个指针所指向的位置,在并发情况下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。解决这个问题有两种方案,

一种是对分配内存空间的动作进行同步处理——实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性;

另一种是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation
Buffer,TLAB)。哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。

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

接下来,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头(ObjectHeader)之中。根据虚拟机当前的运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。

在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从Java程序的视角来看,对象创建才刚刚开始——方法还没有执行,所有的字段都还为零。所以,一般来说(由字节码中是否跟随invokespecial指令所决定),执行new指令之后会接着执行方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。

总结

  • 虚拟机遇到new时,首先检查在常量池是否能找到类的符号引用
  • new时需要为对象分配内存
  • 内存分配方式有两种

java对象创建的细节相关推荐

  1. Java 并发编程解析 | 如何正确理解Java对象创建过程,我们主要需要注意些什么问题?

    苍穹之边,浩瀚之挚,眰恦之美: 悟心悟性,善始善终,惟善惟道! -- 朝槿<朝槿兮年说> 写在开头 从接触 Java 开发到现在,大家对 Java 最直观的印象是什么呢?是它宣传的 &qu ...

  2. 【JVM】Java对象创建的流程步骤

    · 本文摘要 · 罗列Java创建对象的各种方式: · 讲解Java对象创建的流程步骤: 一.Java创建对象的各种方式 · 1. 用关键字new,老少皆知的方法:StringBuffer sb = ...

  3. java对象创建的流程到底是什么样子的?new一个对象是真的直接放在堆里吗?其实大有学问!

    目录 对象创建流程图 总结 逃逸分析 什么是逃逸分析? 对象逃逸状态 逃逸分析优化 TLAB区 对象如何进入老年代 有问题可以直接留言讨论~ 对象创建流程图 1.编译器通过逃逸分析,确定对象是在栈上分 ...

  4. java 对象创建过程_5种创建Java对象的方式

    在本篇文章中,将介绍5种创建Java对象的方式.类是创建对象的基本模板,接下来将介绍5种不同的方式,利用Java类来实例化Java对象. 1. 使用new关键字 ​ 采用new关键字实例化对象是Jav ...

  5. java创建子类对象的步骤_一通Spring骚操作:我敢说没人比我更懂Java对象创建

    一.开篇一问 一个Spring Bean是Java对象吗?那么一个对象是Spring Bean吗? 带着这个问题我们一起来回顾Spring的生命周期流程,彻底了解一个类在Spring中究竟做了哪些操作 ...

  6. Java:对象创建和初始化过程

    1.Java中的数据类型     Java中有3个数据类型:基本数据类型(在Java中,boolean.byte.short.int.long.char.float.double这八种是基本数据类型) ...

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

    这里以HotSpot为例,且所说的对象指普通的Java对象,不包括数组和Class对象等. 1.对象创建的过程 1.类加载.解析.初始化:虚拟机遇到new时先检查此指令的参数是否能在常量池中找到类的符 ...

  8. Java对象创建的方式(简洁明了)

    前言 在Java中有一句比较流行的话,叫做"万物皆对象",这是Java语言设计之初的理念之一.我们每天创建很多对象,那你知道Java中创建对象的方式有几种吗? 本文将介绍Java创 ...

  9. Java对象创建、分配、布局、访问小析(HotSpot虚拟机)(二)

    本文内容总结自周志明先生所编著的<深入理解Java虚拟机-JVM高级特性与最佳实践>此书的经典不必多说.本节内容是对象的内存布局. 在HotSpot虚拟机中,对象在内存中存储的布局可以分为 ...

最新文章

  1. COGS2355 【HZOI2015】 有标号的DAG计数 II
  2. Linux命令 -- ps
  3. burst tx 功能 开启_Serverspeeder 锐速config配置文件详解
  4. oracle中关于删除表purge语句和闪回语句的基本使用
  5. 细说php这么难懂,挺难懂的解决方法
  6. ndk学习6: 使用gdb调试ndk程序一
  7. AGC030D - Inversion Sum
  8. matlab相机标定 外参数,相机外参数的标定.doc
  9. linux ssh 远程会话保存,远程SSH会话和流程在断开后运行的5种方法
  10. 数据库三范式,轻松理解
  11. 信号与系统考研复习例题详解_小语种日语日本文学复习考研资料加藤周一《日本文学史序说(上)》笔记和考研真题详解...
  12. read()/write()的生命旅程之二——第二章:read()
  13. (转)AI vs 深度学习 vs 机器学习:人工智能的 12 大应用场景
  14. 智能硬件再下一城:家居
  15. 计量经济学及Stata应用 陈强 第九章模型设定与数据问题习题9.3
  16. 花生壳内网穿透+https+tomcat不能进行网页访问
  17. 最新服务器cpu14纳米,英特尔CPU路线图 14nm活力不减 7nm不远了
  18. [BLE]低功耗蓝牙介绍
  19. MATLAB设计FIR数字滤波器GUI界面
  20. python哈姆雷特词频统计_【Python】哈姆雷特字数统计

热门文章

  1. Spark算子--Scala版本 educoder
  2. jupyterlab nb_conda 增加 删除_Jupyter lab
  3. 520这个日子就应该用程序员最浪漫的表白方式
  4. ngrok 代理访问
  5. Linux下静态库.a与.so库文件的生成与使用
  6. 惠农补贴一折通计算机审计方法,审计惠农补贴资金的方法有哪些
  7. 路径规划;a*算法 demo_路径规划A*算法
  8. python的枚举函数_enumerate()函数~~返回一个枚举对象
  9. c语言位运算知乎,07-C语言运算符-指趣学院
  10. layer mvc json 中文乱码处理