您好、欢迎来到现金彩票网!
当前位置:2019跑狗图高清彩图 > 向后可达性 >

999%的Java程序员都说不清的问题:JVM中的对象内存布局?

发布时间:2019-07-10 10:01 来源:未知 编辑:admin

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

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

  Unsafe.allocateInstance 方法则没有初始化实例字段,而 new 语句和反射机制,则是通过调用构造器来初始化实例字段。

  可以看到,new语句编译而成的字节码将包含用来请求内存的 new 指令,以及用来调用构造器的 invokespecial 指令。

  本文不是专门介绍invoke系列指令的,我会在后面的文章中介绍invoke系列指令。

  不过在这里我多说一嘴,字节码中的invokespecial指令通常用于调用私有实例方法、构造器,以及使用super关键字调用父类的实例方法或构造器,和所实现接口的默认方法。

  提到构造器,就不得不提到 Java 对构造器的诸多约束。首先,如果一个类没有定义任何构造器的话, Java 编译器会自动添加一个无参数的构造器。

  在JAVA源码中,我们没有定义构造器,但是生成出来的字节码,已经自动帮我们添加了一个无参数的构造器。他使用的invokespecial方法最终调用的是其父类Object类的构造器方法。

  我将讲述JVM的构造器调用原则,那就是,如果子类的构造器需要调用父类的构造器。如果父类存在无参数构造器的话,该调用可以是隐式的。也就是说, Java 编译器会自动添加对父类构造器的调用。

  但是,如果父类没有无参数构造器,那么子类的构造器则需要显式地调用父类带参数的构造器。

  显式调用有两种,一是直接使用“super”关键字调用父类构造器,二是使用“this”关键字调用同一个类中的其他构造器。

  无论是直接的显式调用,还是间接的显式调用,都需要作为构造器的第一条语句,以便优先初始化继承而来的父类字段。

  可以不优先初始化继承来的父类字段吗?可以,如果你能使用字节码注入工具的话。

  当我们调用一个构造器时,它将优先调用父类的构造器,直至 Object 类。这些构造器的调用者皆为同一对象,也就是通过 new 指令新建而来的对象。

  事实上,我上面的陈述意味着:通过 new 指令新建出来的对象,它的内存其实涵盖了所有父类中的实例字段。

  也就是说,虽然子类无法访问父类的私有实例字段,或者子类的实例字段隐藏了父类的同名实例字段,但是子类的实例还是会为这些父类实例字段分配内存的。

  下面我将介绍压缩指针技术。在 Java 虚拟机中,每个 Java 对象都有一个对象头,它由标记字段和类型指针所构成。

  标记字段用以存储 Java 虚拟机有关该对象的运行数据,如哈希码、GC 信息以及锁信息,而类型指针则指向该对象的类。

  在64位的JVM中,对象头的标记字段占 64 位,而类型指针又占了 64 位。也就是说,每一个 Java 对象在内存中的额外开销就是 16 个字节。

  为了尽量较少对象的内存使用量,64位JVM引入了压缩指针的概念,将堆中原本64位的Java对象指针压缩成32位的。

  这样一来,对象头中的类型指针也会被压缩成32位,使得对象头的大小从16字节降至12字节。

  当然,压缩指针不仅可以作用于对象头的类型指针,还可以作用于引用类型的字段,以及引用类型数组。

  我们规定,默认情况下,JVM堆中对象的起始地址需要对齐至8的倍数,如果一个对象用不到8N 个字节,那么空白的那部分空间就浪费掉了,这些浪费掉的空间我们称之为对象间的填充。

  大家知道,指针里面存放的是地址,由于堆中对象的起始地址是对齐至8的倍数,所以指针存放一个引用(或者对象的类)的内存地址时,根本就不用存放最后的三位二进制数。

  因为所有对象或类的内存地址都对齐了8,所以他们的内存地址的最低三位总是0,32位的指针就可以寻址到 2 的 35 次方个字节,也就是 32GB 的地址空间(超过 32GB 则会关闭压缩指针)。

  我们可以通过配置虚拟机的内存对齐选项来进一步提升寻址范围。但是,这同时也可能增加对象间填充,导致压缩指针没有达到原本节省空间的效果。

  就算是关闭了压缩指针,Java 虚拟机还是会进行内存对齐。此外,内存对齐不仅存在于对象与对象之间,也存在于对象中的字段之间。

  比如说,Java 虚拟机要求long字段、double字段,以及非压缩指针状态下的引用字段地址为8的倍数。

  CPU的缓存行机制大家应该有所耳闻,如果字段不是对齐的,那么就有可能出现跨缓存行的字段。

  该字段的读取可能需要替换两个缓存行,而该字段的存储也会同时污染两个缓存行。

  我们将在后期文章关于volatile关键词的本质分析的过程中,再次考察到CPU缓存行的相关机制。

  最后我要提一句的是,字段重排列技术,就是我刚才提到的,对象的字段之间存在的内存对齐。这指的是重新分配字段的先后顺序,以达到内存对齐的目的

  其一,如果一个字段占据C个字节,那么该字段的偏移量需要对齐至NC。这里的偏移量指的是字段地址与对象的起始地址差值。

  以Long类为例,它仅有一个long类型的实例字段。在使用了压缩指针的 64 位虚拟机中,尽管对象头的大小为12个字节,该 long 类型字段的偏移量也只能是16,而中间空着的4个字节便会被浪费掉。

  说白了,比如B继承了A,A是B的父类,A中所有的字段,在B中都有,而且是先放A的字段,再放B的字段。而且B类对象放A类字段时,需要与父类对应字段的偏移量保持一致。

  假设两个线程分别访问同一对象中不同的 volatile 字段,逻辑上它们并没有共享内容,因此不需要同步。

  如果这两个字段恰好在同一个缓存行中,那么对这些字段的写操作会导致缓存行的写回,也就造成了实质上的共享。

  Java8还引入了一个新的注释@Contended,用来解决对象字段之间的虚共享。

  Java 虚拟机会让不同的@Contended字段处于独立的缓存行中,因此你会看到大量的空间被浪费掉,避免无谓的缓存行同步操作。

  本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。

  一个int类型4占4个字节的内存,一个byte一个字节。但是他们的封装类型Integer,Byte对象内存损耗还是一样的吗?并不是,而且差距十分大。  HotSpot虚拟机中,一个普通的Java对象由...博文来自:bruce128的专栏

  java对象内存布局: markword(记录hashCode值和锁的标识等等) class对象指针 类字段 补齐位如果是数组对象,2、3之间应该加上数组长度布局排列表: ...博文来自:MissNull的博客

  在前面文章了解到Java对象实例是如何在Java堆中创建的,下面我们详细了解Java普通对象创建后,在HotSpot虚拟机Java堆中的内存布局是怎样的,可以分为3个区域:对象头(Header)、实例...博文来自:tjiyu的博客

  《深入理解java虚拟机》,很好的解释了JVM的工作原理,下面是我自己在学习这本时,总结的一些笔记,摘自周志明的《深入理解java虚拟机》第二版理解jvm的工作原理,对java员来说是非常必要的。ja...博文来自:LynnOhYeah

  Java类初始化的顺序经常让人犯迷糊,现在本文尝试着从JVM的角度,对Java非继承和继承关系中类的初始化顺序进行试验,尝试给出JVM角度的解释。非继承关系中的初始化顺序对于非继承关系,主类Initi...博文来自:smile4lee的博客

  一言以蔽之,属性(包括父类)都保存在对象本身的存储空间内;本类的实例方法保存在类对象中,本类的类方法保存在元类对象中;父类的实例方法保存在各级superclass中,父类的类方法保存在各级superm...博文来自:xiaolinyeyi的专栏

  在上篇文章《戳我》中,简单说了继承的三种分类:单继承、多重继承、重复继承。一般的如果没有虚函数,那对象的内存布局就如我们看到的一样,定义了几个变量根据字节对齐就能算出其在内存中所占字节大小。但是有了虚...博文来自:zhuoya_的博客

  本文介绍一个C++struct/class在内存中的布局是什么样的,包括数据成员和方法成员,静态成员,非静态成员,虚拟成员在内存中的位置;本文不涉及(多)继承情况下对象内存布局的细节。...博文来自:giantpoplar的专栏

  一、JVM概述 ①所有的java代码都是在虚拟机中运行的。 ②一次编译,到处运行。JVM可以和不同的操作系统交互。Java是一门跨平台性语言。二、JVM、JDK、JRE区别 JDK:(JavaDeve...博文来自:zhou870498的博客

  深入理解JVM——Java的四种引用级别前言首先,请深刻理解引用计数法和可达性分析算法,详情请参阅点击打开链接。HotSpot采取了可达性分析算法用来判断对象是否被能被GC,无论是引用计算法还是可达性...博文来自:团子

  1.什么叫内存布局?程序是由数据和方法组成的,运行程序则需要内存承载,内存是如何承载程序中的数据和方法的,就描述了程序运行时的内存结构,即内存布局。可见,讨论内存布局的具体细节需要在运行时。2.C执行...博文来自:forwardto9的专栏

  对象在内存中的布局可以分为3块区域:对象头(Header)、实例数据(Instancedata)和对齐填充(Padding)。对象头对象运行时数据HashCodeGC分代年龄锁状态标志线程持有的锁偏向...博文来自:Marshall

  HotSpot虚拟机中,对象在内存中的存储布局分3部分:对象头,实例数据,对齐填充。一.     对象头对象头包含两部分信息:对象的运行时数据和类型指针。1.   对象的运行时数据对象的运行时数据非常...博文来自:超频化石鱼的博客

  摘要:博主JVM系列都是跟随周志明先生的《深入了解JAVA虚拟机》一书来学习,记录并尝试解释下书中一些晦涩知识点,方便自己复习,如果能帮到他人,十分荣幸。在HotSpot虚拟机中,对象在内存中存储的区...博文来自:的博客

  在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头、实例数据、和对齐填充,各个区域的所包含的内容以及起到的作用,如下图展示: ......博文来自:深蓝

  概述一个对象本身的内在结构需要一种描述方式,这个描述信息是以字节码的方法存储在方法区中的。Class本身就是...博文来自:suixinsuoyu12519的专栏

  我们每天都在new对象,但是我们却对对象一无所知!在内存中对象的内容分为三块: 对象头:Markword:hashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间截等;   ...博文来自:的博客

  一聊到JVM,首先要想到为什么需要虚拟机因为java的跨平台,就是通过虚拟机来实现的JVM的原理1。类加载机制类加载机制需要知道的是双亲委派,会先把请求委派给父类加载BootstrapClassloa...博文来自:伟大是熬出来的

  最好看一下前一篇的C++虚函数表简而言之,我们一个类可能会有如下的影响因素:1)成员变量2)虚函数(产生虚函数表)3)单一继承(只继承于一个类)4)多重继承(继承多个类)5)重复继承(继承的多个父类中...博文来自:hacker00011000的专栏

  前言为了更清晰的说明类的内存布局,首先说明下一个执行程序的内存格局,通常其包含:全局数据区,代码区,栈区,堆区。全局数据区存放全局变量,静态数据和常量;代码段存放函数实现;栈区存放为函数运行而分配的局...博文来自:MyWorkingRoom

  可能我们之前就只知道java语言跨平台的实现是因为有针对不同平台有对应的虚拟机。刚开始编程的时候发现内存溢出了,然后就改了下虚拟机的参数,发现就能正常跑了,后面我们的项目上线了,由于有大量的用户访问,...博文来自:JavaCoder_juejue的博客

  基本使用方法VS编译器(这里使用的是:VS2013)可以通过”开发人员命令提示“查看C++类的内存布局,非常有用。双击”VS2013开发人员命令提示“,出现如下界面:进入测试代码所在的目录:测试代码如...博文来自:秋叶原 && Mike 麦克

  如果你是一个Java程序员,想要学习一些更多的编程语言来扩展你的知识和技能,但不知道选择哪种编程语言,那么你已经来到了正确的地方。在本文中,我将分享3种Java程序员可以在2018年学习的JVM语言,...博文来自:软件大咖

  Cpuload的参数如果为4,描述一下现在系统处于什么情况什么对象会从新生代晋升到老年代Linux查看cpu占用率高的进程说一下JVM内存模型把,有哪些区,分别干什么的说一下gc算法,分代回收说下Jv...博文来自:lhx的博客

  一、永久代在说java8内存模型之前先说一下永久代的概念。在Java虚拟机(JVM)内部,class文件中包括类的版本、字段、方法、接口等描述信息,还有运行时常量池,用于存放编译器生成的各种字面量和符...博文来自:keep_trying的专栏

  前言Java是门面向对象的开发语言,那么我们自己编写的Java类生成的对象是什么样的?它肯定保存在虚拟机的内存中,但它以怎样的结构来保存的呢?带着疑问往下看看。关于KlassJava层的开发可能不太熟...博文来自:seaboat——a free boat on the sea.(公众号:远洋号)

  关于数组,我们首先要知道的是,他是引用数据类型,数组是存储同一种数据类型多个元素的容器。数组既可以存储基本数据类型,也可以存储引用数据类型。数组有两种初始化方式,动态初始化和静态初始化.以下通过介绍两...博文来自:znmdwzy的博客

  原文:iOS面试题大全每一个对象内部都有一个isa指针,指向他的类对象,类对象中存放着本对象的:对象方法列表(对象能够接收的消息列表,保存在它所对应的类对象中)。成员变量的列表。属性列表。类对象内部也...博文来自:weixin_33720452的博客

  前言在Java程序中,我们拥有多种新建对象的方式。除了最为常见的new语句之外,我们还可以通过反射机制、Object.clone方法、反序列化以及Unsafe.allocateInstance方法来新...博文来自:吹雪的专栏

  作者:转载或者引用请注明出处!首先梳理一下JVM虚拟机的内存布局:    JDK版本lt;1.8:              拿线程是否可以共享作为分类:1.被所有线程共享【方法区(含运行时...博文来自:PioneerX_x的博客

  在前面两篇文章中了解到Java对象实例是如何在HotSpot虚拟机的Java堆中创建的,以及创建后的内存布局是怎样的。下面详细了解在Java堆中的Java对象是如何访问定位的:先来了解referenc...博文来自:tjiyu的博客

  《深入理解java虚拟机》“大对象对虚拟机的内存分配来说是一个坏消息(替java虚拟机抱怨一句,比遇到一个大对象更加坏的消息就是遇到一群朝生夕灭的短命大对象,写程序时应当避免)”什么是短命的大对象?比...博文来自:afa007的专栏

  一、内存布局:   一个java对象在内存中可分为3个区域:对象头(Header)、实例数据(InstanceData)、对齐填充(Padding)。对象头(两部分): 对象自身运行时的数据。如哈希码...博文来自:微笑浮尘的专栏

  static修饰符的特点:1.属于类不属于对象,随着所在类的加载而加载(当JVM把字节码加载进JVM的时候,static修饰的成员已经在内存中存在了)2.优先于对象存在(对象是手动通过new创建出来的...博文来自:ziyonghong的博客

  进入主题前,先把工具设置好。本文使用编译测试环境:VisualStudio2013VS2013查看类内存布局设置方式如下截图:先选择左侧的C/C++-命令行,然后在其他选项这里写上/d1report...博文来自:Do-Program的专栏

  我在想,程序员都是话少吗?不一定吧,像我和我的同学,都是话很多啊。但是经历过很多事的现在,再想想,发现事实的确如此,程序员确实话少。我是一名实习的程序员。话少钱少死的早。...博文来自:CSDN 官方博客

  JVM是如何识别到低该调用哪个方法的:JVM是根据类名+方法名+方法描述符(形参+返回类型) 来识别到底该调用哪一个方法的。其中,重载方法的匹配优先级规则如下(Java中的重载不会根据返回类型来区分)...博文来自:淡定一生2333的博客

  new一个对象时Jvm做了哪些事情:之前没有进行过类加载(1)类加载并初始化类中的静态属性(赋默认值,如果静态属性有自己赋值,则显示自己赋的值)                     (2)执行静态...博文来自:的博客

  帐号相关流程注册范围n企业n政府n媒体n其他组织换句话讲就是不让个人开发者注册。 :)填写企业信息不能使用和之前的公众号账户相同的邮箱,也就是说小程序是和微信公众号一个层级的。填写公司机构信息,对公账...博文来自:小雨同学的技术博客

  jquery/js实现一个网页同时调用多个倒计时(最新的)nn最近需要网页添加多个倒计时. 查阅网络,基本上都是千遍一律的不好用. 自己按需写了个.希望对大家有用. 有用请赞一个哦!nnnn//jsn...博文来自:Websites

  command窗口是命令窗口,即为sqplus窗口,有命令提示符,识别sqlplus命令,基本的命令都可以执行nsql仅可执行DDL、select、DML等...博文来自:Ape55的博客

  对象的创建和销毁在一定程度上会消耗系统的资源,虽然jvm的性能在近几年已经得到了很大的提高,对于多数对象来说,没有必要利用对象池技术来进行对象的创建和管理。但是对于有些对象来说,其创建的代价还是比较昂...博文来自:赶路人儿

  扫二维码关注,获取更多技术分享nnn 本文承接之前发布的博客《 微信支付V3微信公众号支付PHP教程/thinkPHP5公众号支付》必须阅读上篇文章后才可以阅读这篇文章。由于最近一段时间工作比较忙,...博文来自:Marswill

  记得很早以前公司项目中添加过移动支付这一块, 包括微信,支付宝,银联等第三方的整合。 但是后来懒于总结就没留下什么, 最近公司项目打算添加,所以打算简单总结一下,记上一笔以备将来使用。 毕竟第三方的支...博文来自:samuelnotes的专栏

  本篇文章是根据我的上篇博客,给出的改进版,由于时间有限,仅做了一个简单的优化。相关文章:将excel导入数据库2018年4月1日,新增下载地址链接:点击打开源码下载地址十分抱歉,这个链接地址没有在这篇...博文来自:Lynn_Blog

  最近比较有空,大四出来实习几个月了,作为实习狗的我,被叫去研究Docker了,汗汗!nnDocker的三大核心概念:镜像、容器、仓库n镜像:类似虚拟机的镜像、用俗话说就是安装文件。n容器:类似一个轻量...博文来自:我走小路的博客

  wanghuawei19930812:明白了这些,再回过头去利用IDE进行自动化编译和部署的时候,就会清楚得知道自己需要配置哪些文件,而不会盲目。

http://chinoamobi.com/xianghoukedaxing/278.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有