`

java对象的内存布局及创建过程

    博客分类:
  • jvm
阅读更多
一、对象的内存布局
   对象的内存结构又可以被分为:对象头,实例数据,对象填充
  
   对象头:对象头结构在32位JVM与64位JVM中的实现细节是不同的
32bit:

64bit:

   实例数据:对象真正存储的有效信息,也是在程序代码中定义的各种类型字段内容。无论是从父类继承下来的还是子类定义的,都需要记录下来。

   对象填充:没有实际意义,仅仅起着占位符的作用。以为对象的大小必须是8字节的整数倍。

二、对象的访问定位

对象的访问定位分为两种:

通过句柄访问对象:



通过指针访问对象:



    两种对象访问方式各有优势,使用句柄访问最大好处是reference中存储的是稳定的句柄地址,在对象被移动是只会改变句柄中的实例数据指针,而reference本身不需要修改。
    使用直接指针访问方式的最大好处是速度快,他节省了一次指针定位的时间开销。

三、对象的创建过程

这里主要讨论实例化普通对象的过程,不包括数组和Class对象。

1、检查指令的参数是否可以在常量池中定位到一个类的符号引用

2、检查这个符号引用代表的类是否被加载,解析初始化过

3.1、如果被加载并初始化了继续下一步

3.2、如果没有没有初始化,那么先执行类的加载过程

4、位新生对象分配内存(两种方法)

   1)指针碰撞
        如果Java 堆当中的内存是规则的,已使用内存在一边,未使用内存在另外一边, 中间  放着一个指针作为分界点的指示器,如果需要分配内存就只需要把指针向空闲空间那边挪动一段与对象大小相等的距离

   2)空闲列表
        如果已用内存和空闲内存是交互存在的,这样虚拟机就必须维护一个列表,记录哪块内存是可用的,在分配内存的时候从列表中找到一个足够大的空间划分给对象实例,并且更新空闲列表。

    分配内存时可能出现的问题:并发创建对象会出现指针没来得及修改导致的重复地址覆盖对象
    解决办法:
   

        
  • 分配内存动作同步-采用 CAS配上失败重试方式保证更新操作的原子性
  •     
  • 预先给 Java 线程在堆中分配一小块内存,称为本地线程分配缓冲(TLAB),只有当该线程用完才需要同步锁。是否使用 TLAB 可以通过 -XX:+/-UseTLAB
  •    


5、将分配到的内存空间都初始化为零值(不包括对象头)

6、对对象进行必要的设置
   例如:
  

      
  • 设置这个对象是哪个类的实例
  •   
  • 如何才能找到类的元数据信息
  •   
  • 对象的hash码
  •   
  • 对象的GC分代年龄
  •   
  • 是否启用偏向锁
  •   


7、执行<init>方法,可以根据一段代码来讨论变量的具体初始化过程:

class Parent {

	private int p_01 = getP_01();
	private static int p_02 = getP_02();
	{
		System.out.println("I am Parent Local code block");
	}
	static {
		System.out.println("I am Parent static code block");
	}
	public Parent() {
		System.out.println("I am Parent Constructor!");
	}
	private int getP_01() {
		System.out.println("p_01 is initialized!");
		return 13;
	}
	private static int getP_02() {
		System.out.println("static p_02 is initialized!");
		return 14;
	}
}

class Son extends Parent {
	private int s_01 = getS_01();
	private static int s_02 = getS_02();
	{
		System.out.println("I am Son Local code block");
	}
	static {
		System.out.println("I am Son static code block");
	}
	public Son() {
		System.out.println("I am Son Constructor!");
	}
	private int getS_01() {
		System.out.println("s_01 is initialized!");
		return 13;
	}
	private static int getS_02() {
		System.out.println("static s_02 is initialized!");
		return 14;
	}
}
public class CreateObject {
	public static void main(String[] args) {
		Son s = new Son();
	}
}

执行结果如下:
static p_02 is initialized!
I am Parent static code block
static s_02 is initialized!
I am Son static code block
p_01 is initialized!
I am Parent Local code block
I am Parent Constructor!
s_01 is initialized!
I am Son Local code block
I am Son Constructor!

然后可以总结得出<init>初始化过程如下:
   1)父类静态变量,静态代码块执行初始化(静态变量,静态代码按顺序执行,属于同一优先级)
   2)子类静态变量,静态代码块执行初始化
   3)父类全局变量,代码块被初始化(全局变量,代码按顺序执行,属于同一优先级)
   4)父类构造函数执行
   5)子类全局变量,代码块被初始化
   6)子类构造函数被执行

  误区:其实并不是真的子类构造函数在父类构造函数之后执行,而是在子类构造器的第一行隐式调用了父类的构造函数;
  • 大小: 12.4 KB
  • 大小: 9.5 KB
  • 大小: 47.2 KB
  • 大小: 43.1 KB
0
1
分享到:
评论

相关推荐

    深入理解java对象,包括对象创建和内存分配

    描述对象的创建过程,对象的内存布局,jvm指针压缩,对象访问

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

    主要介绍了深入理解JVM之Java对象的创建、内存布局、访问定位,结合实例形式详细分析了Java对象的创建、内存布局、访问定位相关概念、原理、操作技巧与注意事项,需要的朋友可以参考下

    ObjectLayout, 记住,用可以优化对象布局设计的Java类.zip

    ObjectLayout, 记住,用可以优化对象布局设计的Java类 ObjectLayout[Gitter](https://badges.gitter.im/Join chat 。...ObjectLayout旨在创建一些有用的核心Java类,这些类是用可以优化的内存布局设计有关详细信息,请

    java源码包---java 源码 大量 实例

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    Java开发技术大全(500个源代码).

    useOnlyTest.java 创建多个对象,演示this的作用 useStaticBolck.java 使用静态块 useStVar.java 使用静态成员变量 第4章 示例描述:本章学习继承与多态。 absClass.java 抽象类定义示例 ancestor.java 基类...

    java源码包4

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JVM-Java虚拟机

    对象内存布局;如何访问一个对象;GC基本原理;串行收集器;并行收集器; 能学到什么:1,JVM底层运行机制和原理;2JVM参数;3,垃圾回收原理;4,垃圾回收器的使用;5,调优实战案例 导语:平时我们所说的JVM广义上...

    java源码包3

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA上百实例源码以及开源项目

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA上百实例源码以及开源项目源代码

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    java源码包2

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    疯狂JAVA讲义

    学生提问:构造器是创建Java对象的途径,是不是说构造器完全负责创建Java对象? 141 5.5.2 构造器的重载 142 学生提问:为什么要用this来调用另一个重载的构造器?我把另一个构造器里的代码复制、粘贴到这个构造器...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个...

    JAVA基础课程讲义

    JAVA对象的序列化和反序列化 161 为什么需要序列化和反序列化 161 对象的序列化主要有两种用途 161 序列化涉及的类和接口 162 序列化/反序列化的步骤和实例 162 综合的序列化和反序列化练习 163 JAVA.IO包相关流对象...

    6.1.2.JVM进行篇笔记1

    2.1栈指向堆 2.2 方法区指向堆 2.3 堆指向方法区 2.4 Java对象内存布局 3.1 图解 3.2 对象创建所在区域 3.4 Old区详解 3.5

    Java JVM 面试题总结

    JVM 面试题总结 JVM 的主要作用是什么? 请你描述一下 Java 的内存区域? 请你描述一下 Java 中的类加载...请你说一下对象的内存布局? 对象访问定位的方式有哪些? 如何判断对象已经死亡? 如何判断一个不再使用的类?

    Java语言的科学与艺术 斯坦福大学经典教材

    9.7 编程练习 第10章 事件驱动程序 10.1 Java事件模型 10.2 简单的事件驱动程序 10.3 响应鼠标事件 10.4 响应键盘事件 10.5 创建简单的GUI 10.6 Swing 交互器层次结构 10.7 管理组件布局 10.8 使用TableLayout类 ...

    【JVM和性能优化】1.Java内存区域

    文章目录了解的必要性JVM历史JVM数据区域私有区共有区内存区域版本变化1.61.71.8元空间栈跟堆Java中的对象都是在堆中分配吗逃逸分析标量替换栈上分配同步消除JVM对象对象创建过程对象内存布局对象访问方式通过句柄...

    深入理解Java虚拟机视频教程(jvm性能调优+内存模型+虚拟机原理)视频教程

    第29节对象在内存中的布局-对象的创建00:21:19分钟 | 第30节探究对象的结构00:13:47分钟 | 第31节深入理解对象的访问定位00:08:01分钟 | 第32节垃圾回收-概述00:06:20分钟 | 第33节垃圾回收-判断对象是否存活...

    JAVA面试题最全集

    除了使用new关键字创建对象意外,试列举另外三种以上创建实例的方式? 37.classloader中,JDK的API、Classpath中的同web-inf中的class加载方式有什么区别? 38.列举三种以上垃圾回收算法,并比较其优缺点? 39....

Global site tag (gtag.js) - Google Analytics