Java对象在内存中是怎么分配的如何存储的

比如一个类通过构造函数初始化各个成员变量生成一个对象,new出来的对象存放在堆内存对象中对象是由各个成员构成的,请问这些成员也存在堆里吗是怎样的存储形式?... 比如一个类通过构造函数初始化各个成员变量生成一个对象,new出来的对象存放在堆内存对象中对象是由各个成员构成的,请问這些成员也存在堆里吗是怎样的存储形式?

java中数组是以对象形式存在的栈中存储的是数组对象的地址(即引用),而对象本身不存放在栈Φ而是存放在堆中,使用时通过栈中的引用地址找到堆中的实际对象这里的引用地址类似于C/C++中的指针。

你对这个回答的评价是

java中数組是以对象形式存在的,栈中存储的是数组对象的地址(即引用)而对象本身不存放在栈中,而是存放在堆中使用时通过栈中的引用地址找到堆中的实际对象,这里的引用地址类似于C/C++中的指针

你对这个回答的评价是?

下载百度知道APP抢鲜体验

使用百度知道APP,立即抢鲜体验你的手机镜头里或许有别人想知道的答案。

}

Java内存对象分配时涉及的区域:

寄存器:在程序中无法控制;

栈:存放基本类型的数据和对象的引用但是对象本身不存放在栈中,而是存放在堆中;

堆:存放用new产生的数據;

静态域:存放在对象中用static定义的静态成员;

  1. 在函数中定义的一些基本类型的变量数据还有对象的引用变量都在函数的栈内存对象中汾配。当在一段代码中定义一个变量时Java就在栈中为这个变量分配内存对象空间,当该变量退出该作用域后java会自动释放掉为该变量分配嘚内存对象空间。

  2. 栈内存对象是java程序的运行区,是在线程创建时创建的它的生命周期跟随线程的生命周期,线程结束栈内存对象也就釋放对于栈来说不存在垃圾回收问题,只要线程结束该栈就结束了。

  3. 栈中的数据是以栈帧(stackframe)的格式存在的栈帧是一个内存对象区塊,是一个数据集是有关方法(method)和运行期数据的数据集。当一个方法A被调用时就会产生一个栈帧F1被压入到栈中A方法再调用B方法,就會产生栈帧F2被压入栈执行完毕后,先弹出F2在弹出F1。

  4. 堆内存对象用来存放由关键字new创建的对象和数组在堆中分配的内存对象,由java虚拟機自动垃圾收集器来管理

  5. 在堆中创建一个对象后,还可以在栈中定义一个变量让这个变量的值等于对象在堆内存对象中的首地址,栈Φ的变量就是对象的引用相当于java中的指针。当程序运行到对象所在的语句块之外对象占据的内存对象不会自动释放,在没有引用变量指向它时随后一个不确定的时间被垃圾收集器回收掉。

  6. 常量池指的是在编译期被确定并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(intlong等)和对象型(string、数组等)的常量值(final),还包含一些以文本形式出现的符号引用

    在程序执行时,瑺量池会存储在MethodArea(方法区)中而不是堆中。

  1. 一个java虚拟机实例只存在一个堆内存对象堆内存对象的大小是可以调节的,类加载器读取了类文件后需要把类、方法、常变量(const修饰的变量)放到堆内存对象中,堆内存对象分为三部分:

  2. 永久存储区是一个常驻内存对象区域用于存放jdk自身所携带的ClassInterface的元数据。也就是说它存储的是运行环境必需的类信息被装载到此区域的数据不会被垃圾收集器回收,关闭java虚拟机才會释放此区域占的内存对象

  3. 新生区是类的诞生、成长、消亡的区域,新生区又分两部分:伊甸区(Edenspace)和幸存区(Survivorspace)所有的类都是在伊甸区被new出来的。幸存区有两个:0区(survivor0 space)和1区(survivor1space)当伊甸区的空间用完时,程序再创建对象虚拟机将对伊甸区进行垃圾回收,将伊甸区Φ的不再被引用的对象进行销毁然后将伊甸区中的剩余对象移动到幸存0区,如果幸存0区也满了将对该区进行垃圾回收,然后移动到1区如果1区也满了,就会移动到老年区

  4. 老年区保存从新生区帅选出来的java对象。

Java虚拟机中为什么分堆区栈区?

  1. 1)从软件的角度栈区代表叻处理逻辑,而堆代表了数据分开,使得处理逻辑更为清晰体现了模块化的思想。

  2. 2)虚拟机堆、栈的分离使得堆中的内容可以被多個虚拟机栈共享(也可以理解为多个线程访问同一个对象,因为虚拟机栈是随着线程的创建而创建的)这种共享的益处很多,一方面提供了一种有效的数据交互方式(如共享内存对象);另一个方面堆中的共享常量和缓存可被多有虚拟机栈访问,节省了空间

经验内容僅供参考,如果您需解决具体问题(尤其法律、医学等领域)建议您详细咨询相关领域专业人士。

}

了解 Java 对象从被创建、存储 & 怎么被使用的整个过程十分重要对应过程则是:对象创建、对象内存对象布局、对象访问定位的三个过程本文将本文我对 Java 对象创建、对象内存對象布局、对象访问定位的三个过程 进行了详细介绍,希望你们会喜欢

在开发使用时创建 Java 对象仅仅只是是通过关键字new:A a = new A();可是 Java对象在虚擬机中创建则是相对复杂。今天我将详解Java对象在虚拟机中的创建过程限于普通对象,不包括数组和Class对象等

当遇到关键字new指令时Java对象创建过程便开始,整个过程如下:

下面我将对每个步骤进行讲解

检查 该new指令的参数 是否能在 常量池中 定位到一个类的符号引用检查 该类符號引用 代表的类是否已被加载、解析和初始化过如果没有,需要先执行相应的类加载过程

步骤2:为对象分配内存对象

虚拟机将为对象分配內存对象即把一块确定大小的内存对象从 Java 堆中划分出来对象所需内存对象的大小在类加载完成后便可完全确定

关于分配内存对象,此处主要讲解内存对象分配方式内存对象分配 根据 Java堆内存对象是否绝对规整 分为两种方式:指针碰撞 & 空闲列表Java堆内存对象 规整:已使用的内存對象在一边未使用内存对象在另一边Java堆内存对象 不规整:已使用的内存对象和未使用内存对象相互交错

假设Java堆内存对象绝对规整,内存對象分配将采用指针碰撞分配形式:已使用内存对象在一边未使用内存对象在另一边,中间放一个作为分界点的指示器

那么分配对象內存对象 = 把指针向 未使用内存对象 移动一段 与对象大小相等的距离

假设Java堆内存对象不规整,内存对象分配将采用 空闲列表分配形式:虚拟機维护着一个 记录可用内存对象块 的列表在分配时从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录额外知识

分配方式的选择 取决于 Java堆内存对象是否规整;而 Java堆是否规整 由所采用的垃圾收集器是否带有压缩整理功能决定因此:使用带 Compact 过程的垃圾收集器时,采用指针碰撞;如Serial、ParNew垃圾收集器

使用基于 Mark_sweep算法的垃圾收集器时采用空闲列表。如 CMS垃圾收集器

对象创建在虚拟机中是非常频繁的操莋即使仅仅修改一个指针所指向的位置,在并发情况下也会引起线程不安全如正在给对象A分配内存对象,指针还没有来得及修改对潒B又同时使用了原来的指针来分配内存对象

所以,给对象分配内存对象会存在线程不安全的问题

解决 线程不安全 有两种方案:

同步处理汾配内存对象空间的行为虚拟机采用 CAS + 失败重试的方式 保证更新操作的原子性

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

内存对象分配完成后虚拟机需要将分配到的内存对象空间初始化为零(不包括对象头)

保证了对象的实例字段在使用时可不赋初始值就直接使用(对应值 = 0)如使用本哋线程分配缓冲(TLAB),这一工作过程也可以提前至TLAB分配时进行步骤4: 对对象进行必要的设置

如,设置 这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息

这些信息存放在对象的对象头中

至此从 Java 虚拟机的角度来看,一个新嘚 Java对象创建完毕但从 Java 程序开发来说对象创建才刚开始,需要进行一些初始化操作1.3 总结

下面用一张图总结 Java对象创建的过程

问题:在 Java 对象創建后,到底是如何被存储在Java内存对象里的呢答:在Java虚拟机(HotSpot)中,对象在 Java 内存对象中的 存储布局 可分为三块:对象头 存储区域实例数據 存储区域对齐填充

下面我会详细说明每一块区域

此处存储的信息包括两部分:

对象自身的运行时数据(Mark Word)如哈希码(HashCode)、GC分代年龄、鎖状态标志、线程持有的锁、偏向线程ID、偏向时间戳等该部分数据被设计成1个 非固定的数据结构 以便在极小的空间存储尽量多的信息(会根据对象状态复用存储空间)对象类型指针即对象指向它的类元数据的指针虚拟机通过这个指针来确定这个对象是哪个类的实例特别注意

洳果对象 是 数组,那么在对象头中还必须有一块用于记录数组长度的数据

因为虚拟机可以通过普通Java对象的元数据信息确定对象的大小但昰从数组的元数据中却无法确定数组的大小。

2.2 实例数据 区域

存储的信息:对象真正有效的信息即代码中定义的字段内容

从分配策略中可以看出相同宽度的字段总是被分配到一起// 在满足这个前提的条件下,父类中定义的变量会出现在子类之前CompactFields = true;// 如果 CompactFields 参数值为true那么子类之中較窄的变量也可能会插入到父类变量的空隙之中。2.3 对齐填充 区域

存储的信息:占位符占位作用

因为对象的大小必须是8字节的整数倍而因HotSpot VM的偠求对象起始地址必须是8字节的整数倍且对象头部分正好是8字节的倍数。因此当对象实例数据部分没有对齐时(即对象的大小不是8字節的整数倍),就需要通过对齐填充来补全2.4 总结

问:建立对象后,该如何访问对象呢实际上需访问的是 对象类型数据 & 对象实例数据

答:Java程序 通过 栈上的引用类型数据(reference) 来访问Java堆上的对象由于引用类型数据(reference)在 Java虚拟机中只规定了一个指向对象的引用,但没定义该引用應该通过何种方式去定位、访问堆中的对象的具体位置

所以对象访问方式取决于虚拟机实现目前主流的对象访问方式有两种:

句柄 访问矗接指针 访问具体请看如下介绍:

本文我对 Java 对象创建、对象内存对象布局、对象访问定位的三个过程 进行了详细介绍在接下来的日子,我會推出一系列讲解JVM的文章具体如下;

请可免费领取java资料一份 你的鼓励是我写作的最大动力!

不定期分享关于安卓开发的干货,追求短、岼、快却不缺深度

}

我要回帖

更多关于 对象在内存中是怎么分配的 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信