Java 创建对象的方式

1:new 语句和反射机制创建。该方式会调用类的构造器,同时满足诸多约束。如果一个类没有构造器的话,Java 编译器会自动添加一个无参数的构造器。子类的构造器需要调用父类的构造器,如果父类存在无参数构造器的话,该调用可以是隐式的。如果父类没有无参数构造器,那么子类的构造器则需要显式的调用父类带参数的构造器。

显式调用又可以分为两种,一种是使用“super”关键字调用父类构造器,二是用“this”关键字调用同一个类中的其他构造器。无论是直接或者间接的显式调用,都需要作为构造器的第一条语句,以便优先初始化继承而来的父类字段。

2:Object.clone 方法和反序列化通过直接复制已有的数据,来初始化新建对象的实例字段。

在通过调用构造器创建对象的时候,子类的实例会为父类实例字段分配内存。下面总结一下,这些字段在内存中是怎么具体分布的。

压缩指针

在 Java 虚拟机中,每个 Java 对象都有一个对象头,是由标记字段和类型指针所构成。标记字段用来存储 Java 虚拟机有关该对象的运行数据,如哈希码,GC信息以及锁信息;而类型指针则指向该对象的类。

在 64 位的 Java 虚拟机中,对象头的标记字段占 64 位,而类型指针又占了 64 位,总共 16 字节。也就是说,每个 Java 对象在内存的中的额外开销就是 16 个字节。例如:Integer,仅有一个 int 类型的私有字段,占 4 个字节,但是 Integer 的额外开销确实 16 字节。这也是为什么 Java 要引入基本类型的原因之一。

为了减少内存使用量,64 位 Java 虚拟机引入了压缩指针的概念,讲原本 64 位的 Java 对象指针压缩成 32 位的。如此一来,对象头的类型指针也会被要说成 32 位,标记字段并未压缩,使得对象头大小变为 12 字节。

压缩指针的原理:
举例:马路上停了一堆房车,每个房车占据两个车位,总共有 32 个车位,车位排号依次从 0 到 31。我们约定,停在 0 号和 1 号车位上的车是 0 号车,停在 2 号和 3 号车位上的车是 1 号车,以此类推。

原始的内存寻址放的是车位号。比如一个指针的值为 6 ,代表 6 这个车位,找到车位就可以找到 3 号车。采用压缩指针的方式,指针中的值存储的是车号,比如 3 代表的就是 3 号车,然后根据停车规则可以知道在 6 号车位上可以找到 3 号车。

压缩指针就是 JVM 采用封装转化的方法优化了存储结构,自动帮我们实现 32 位的内存地址与 64 位的内存地址的映射。当然,上述情况下对内存数据的查找,需要满足一个前提:数据的存储的起始位置需要对齐字段所占存储空间的整数倍。例如:不开启指针压缩的时候,Java 虚拟机堆中对象的起始地址需要对其至 8 的倍数。如果一个对象用不到 8N 个字节,那么空白的那部分空间就浪费掉了。这些浪费掉的空间我们称之为对象间的填充。

内存字段对其的另一个原因,是让字段只出现在同意 CPU 的缓存中。如果字段不是对齐的,那么就有可能出现跨缓存行的字段。也就是说该字段的读取可能需要替换两个缓存航,而字段的存储也会同时污染两个缓存行。这两种情况对程序的执行效率而言都是不利的。

字段重排列

字段重排列就是 Java 虚拟机重新分配字段的先后顺序,以达到内存对其的目的。Java 虚拟机中有三种排列方法,全都遵循以下两个原则:
1:如果一个字段占据 C 个字节,那么该字段的偏移量需要对其至 NC。这里的偏移量指的是字段地址与对象的起始地址差值。

举例:Long 类,仅有一个 long 类型的实例字段。在 64 为虚拟机中使用压缩指针后,对象头的大小为 12 个字节,该 long 类型字段的偏移量只能是 NC = 2*8 = 16,而中间空着的 4 个字节便会被浪费掉。

2:子类所继承字段的偏移量,需要与父类对应字段的偏移量保持一致。

总结

本文创作灵感来源于 极客时间 郑雨迪老师的《深入拆解 Java 虚拟机》课程,通过课后反思以及借鉴各位学友的发言总结,现整理出自己的知识架构,以便日后温故知新,查漏补缺。

关注本人公众号,第一时间获取最新文章发布,每日更新一篇技术文章。

10 Java 对象的内存布局的更多相关文章

  1. Java对象的内存布局

    对象的内存布局 平时用java编写程序,你了解java对象的内存布局么? 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域: 对象头 实例数据 对齐填充 对象头 对象头包括两部分信息: ...

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

    一 Java对象的内存布局 在HotSpot虚拟机中,对象在内存中的布局分为3个区域 对象头(Header) Mark Word(在32bit和64bit虚拟机上长度分别为32bit和64bit)存储 ...

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

    先来看看Java对象在内存中的布局   一 Java对象的内存布局 在HotSpot虚拟机中,对象在内存中的布局分为3个区域 对象头(Header) Mark Word(在32bit和64bit虚拟机 ...

  4. Java对象的内存布局以及对象所需内存大小计算详解

    1. 内存布局 在HotSpot虚拟机中,对象的内存布局可以分为三部分:对象头(Header). 实例数据(Instance Data)和对齐填充(Padding). 1) 对象头(Header): ...

  5. JVM总结-java对象的内存布局

    在 Java 程序中,我们拥有多种新建对象的方式.除了最为常见的 new 语句之外,我们还可以通过反射机制.Object.clone 方法.反序列化以及 Unsafe.allocateInstance ...

  6. 一个Java对象的内存布局

    1.对象的创建过程 class loading class linking(verification,preparation,resolution) class initializing 申请对象内存 ...

  7. 深入理解 Java 对象的内存布局

    对于 Java 虚拟机,我们都知道其内存区域划分成:堆.方法区.虚拟机栈等区域.但一个对象在 Java 虚拟机中是怎样存储的,相信很少人会比较清楚地了解.Java 对象在 JVM 中的内存布局,是我们 ...

  8. java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值

    在上一篇文章中.我们列出了计算java对象大小的几个结论以及jol工具的使用,jol工具的源代码有兴趣的能够去看下.如今我们利用JDK中的sun.misc.Unsafe来计算下字段的偏移地址,一则验证 ...

  9. Object o = new Object()占多少个字节?-对象的内存布局

    一.先上答案 这个问题有坑,有两种回答 第一种解释: object实例对象,占16个字节. 第二种解释: Object o:普通对象指针(ordinary object pointer),占4个字节. ...

随机推荐

  1. LeetCode OJ Container With Most Water 容器的最大装水量

    题意:在坐标轴的x轴上的0,1,2,3,4....n处有n+1块木板,长度不一,任两块加上x轴即可构成一个容器,其装水面积为两板的间距与较短板长之积,以vector容器给出一系列值,分别代表在0,1, ...

  2. 2019年5~6月训练记录(更新ing)

    前言 \(ZJOI\)正式结束了. 但期中考试只考了年级\(216\),退役既视感... 于是就被抓回去补文化课了. 下半个学期可能要以文化课为主了吧! 但周三.周日应该还是会正常参加训练的,但其他时 ...

  3. Matlab 中实用数据结构之 containers.Map

    概要   熟悉 Python 的都知道字典 Dict 类型数据结构功能的强大,Matlab 中虽然有表结构,但是其列名必须是亦变量名类型的字符串,如果我想用数字开头的字符串作键值,其表结构就无能为力了 ...

  4. Solaris&&QNX® Neutrino®&&OpenVMS&&FreeBSD&&AIX

    原文链接Solaris (读作 /se'laris:/ 或者 /so'le:ris/ 或者 '梭拉瑞斯' )是Sun Microsystems研发的计算机 操作系统.它被认为是UNIX操作系统的衍生版 ...

  5. c++ 程序设计question 001:我们的开发工具是什么?

    我们使用的开发工具是dev cpp (c plus plus),这是一个集成开发环境,我们称之为IDE(integrated development environment)

  6. json代码驾照考题批量加入MySQL数据库 ps.executeUpdate()永远只能悲催的加一条数据 去掉id主键自增 用foreach循环数据库只能出现一条语句

    package com.swift; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStrea ...

  7. MintLinux

    最近将我的mintlinux进行了一系列外观优化,总算好看了一点

  8. linux 下备份mysql数据库

    今天老板让备份数据库没办法自己折腾吧,下面把折腾的结果总结总结. 数据库备份思路: 1.编写脚本 2.执行脚本  哈哈,是不是很简单,打开冰箱,放入大象,关上.下面我是具体操作. 一.编写脚本 1.设 ...

  9. PHP跨域请求nodejs

    摘要:用nodejs作为服务器,php作为客服端进行跨域请求,并返回数据. 一:windows环境下的nodejs安装(以及express模板的安装):http://blog.uifanr.com/2 ...

  10. makefile学习(1)

    GNU Make / Makefile 学习资料 GNU Make学习总结(一) GNU Make学习总结(二) 这篇学习总结,从一个简单的小例子开始,逐步加深,来讲解Makefile的用法. 最后用 ...