几乎所有对象都是在堆中分配内存的,这次来讲讲java的对象。

对象的创建主要分为以下几步:

首先,查看类是否装载。当JVM读取到new指令的时候,会拿着符号描述去方法区寻找它所属的类,如果未查找到,则需要先对类进行加载解析初始化;

然后,为对象分配空间。主要涉及两种方式,第一种是指针碰撞法,顾名思义,两个指针挪动,为新来的对象“挪”空间,前提是配合相应的GC算法使堆空间时刻保持连续,同时,如果是多线程还需要考虑同步问题,可以使用CAS或TLAB的方式;第二种是空闲列表法,如果堆空间不连续的话可以采用此方法,每次GC之后把可利用的空间写入到一个列表,通过维护这个列表来得知在哪里给对象分配内存。

分配完内存之后,需要给对象的属性设置零值(不包含对象头的区域),即初始值,如果此时访问对象属性的话得到的将是一个零值。

接下来设置对象头信息,包括对象哈希码,类的地址,对象的GC年龄分代信息,锁状态等。

最后一步就是执行<init>方法,为对象赋值。


对象的大小

对于一个新建的无任何属性的空的Object对象,它的大小为8byte,它的引用变量前面说过,为4byte,因此创建一个空的Object对象需要占用内存12byte;如果建立一个有属性的对象需要多大空间呢?我们来分析一下

class hello{

int a;

boolean b;

Object c;

}

如果要创建这样一个对象,我们知道所有的类都需要继承Object类的,因此首先需要一个8byte的空壳对象,然后int属性占4byte,boolean属性占1byte,引用变量属性占4byte(注意c仅仅是一个引用),占用17字节,而JVM规定,对象空间占用必须为8byte的整数倍,因此需要凑整,也就是这个对象在堆中需要占用24字节大小。

这里还要说一下基本类型的包装类型的对象大小,对于这类对象,即使声明一个空对象,也至少要占用内存为12byte,这还只是个空对象,而且还要凑整,所以需要16字节,这已经是基本类型的2倍以上了,因此我们平时尽量不要使用包装类型的对象,当然,jdk5之后JVM会自动拆箱装箱,对包装类型的内存占用空间也有了一定的优化。


对象头

因为之前在学习锁优化的时候提到了Mark Word,所以这次又着重看了一下这里。对象头是一个无固定格式的,包含对象信息的一段序列。对象头的信息主要分两部分存放

第一块用来存储运行时所需要的信息,叫Mark Word,用来存放如哈希码,GC年龄分代,锁状态标志,偏向线程ID等,对于32位和64位系统,在未开启压缩指针下这部分分别为固定大小32位和64位。在未加锁32位系统下,MarkWord中有25位用来存放对象的哈希码,4bit存放对象的年龄分代信息,2bit存放锁标识位,1bit固定为0;

第二块是一个指向它所属的类的一个类型指针。

对于普通对象,JVM可以通过这个指针很轻易的找到它所属的类信息以及对象大小,但是如果是一个数组对象,通过前面所说的信息还是无法确定这个数组的大小,甚至追溯到数组对象的元数据,因此,对于数组对象,对象头信息还需要一条记录数组长度的数据。


对象的访问定位

如果想通过栈上的reference数据来访问操作对象,有两种方式,第一种是直接指针访问,这是Hotpot使用的访问方式,在引用类型中直接记录下对象的地址,速度快,但是如果频繁GC导致对象在堆中的位置频繁移动,那么该地址每次都需要修改,可能会带来一些性能问题;第二种是句柄访问,即在堆区划分出来一块内存来作为句柄池,栈中的引用类型记录对象的句柄地址,句柄地址中记录对象的实际位置,这样每次移动对象只需要维护句柄池即可,栈区无需修改,相对会稳定一些。总之,两种方式各有优点。

JVM之对象的更多相关文章

  1. JVM中对象的创建过程

    JVM中对象的创建过程如以下流程图中所示: 对其主要步骤进行详细阐述: 为新生对象分配内存: 内存的分配方式: 指针碰撞:假设Java堆中内存是绝对规整的,所有用过的内存放在一边,空闲的内存在另一边, ...

  2. JVM中对象的回收过程

      当我们的程序开启运行之后就,就会在我们的java堆中不断的产生新的对象,而这是需要占用我们的存储空间的,因为创建一个新的对象需要分配对应的内存空间,显然我的内存空间是固定有限的,所以我们需要对没有 ...

  3. Java虚拟机笔记(五):JVM中对象的分代

    为什么要分代 为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用, ...

  4. jvm回收对象

    jvm在判断对象死亡之前需要判断对象是否可到达,方法有引用计数算法和可达性分析算法,jvm采用的是后者.首先来了解一下这两种算法. 引用计数算法: 算法定义 为每个对象增加一个字段记录被引用的次数,并 ...

  5. JVM——深入分析对象的内存布局

    概述 一个对象本身的内在结构需要一种描述方式,这个描述信息是以字节码的方法存储在方法区中的.Class本身就是一个对象,都以KB为单位,如果new Integer()为了表示一个数据就占用KB级别的内 ...

  6. JVM与对象初始化

    一个对象从无到有的过程 A a = new A() 1.JVM遇到new指令就会去堆内存分配一块内存空间,内存的大小在编译期间就可以确定 2.接着调用A的构造函数,这里构造的时候会沿着继承树逆流而上, ...

  7. JVM之对象分配:栈上分配 & TLAB分配

    1. Java对象分配流程 2. 栈上分配 2.1 本质:Java虚拟机提供的一项优化技术 2.2 基本思想: 将线程私有的对象打散分配在栈上 2.3 优点: 2.3.1 可以在函数调用结束后自行销毁 ...

  8. JVM(3)对象A和B循环引用,最后会不会不被GC回收?-------关于Java的GC机制

    ①首先说一下,GC里边在JVM其中是使用的ROOT算法,ROOT算法,什么称作为ROOT呢,就是说类的静态成员,静态成员就是static修饰的那种,是"根"的一个,根还包含方法中的 ...

  9. @JVM中对象的引用类型

    JVM中有四种引用类型:强引用.软引用.弱引用.虚引用   强引用(Stong Reference):是指在程序代码中普遍存在的,类似:Object obj = new Object()这类的引用,只 ...

  10. JVM(二) 对象存活判断和垃圾回收算法

    对象的创建 概述 下面简要介绍创建对象的几个重要步骤 : 检查能否在常量池定位到一个类的符号引用,并检查这个符号代表的类是否已被加载,解析和初始化过.如果没有则执行类加载的操作.(即是说对象的引用放在 ...

随机推荐

  1. 浏览器间CSS样式兼容问题

    1.display:table居中显示 在chrome和safari浏览器上兼容问题 2.滤镜 在chrome浏览器中能正常显示,在360浏览器中不能正常显示 3.省略号问题 对于一行显示,基本上对所 ...

  2. H3C 帧中继子接口

  3. 七个用于数据科学(data science)的命令行工具

    七个用于数据科学(data science)的命令行工具 数据科学是OSEMN(和 awesome 相同发音),它包括获取(Obtaining).整理(Scrubbing).探索(Exploring) ...

  4. css写一个计算器叭

    显示效果如图,emoji可替换为数字.

  5. 如何让索引只能被一个SQL使用

    有个徒弟问我,要创建一个索引,去优化一个SQL,但是创建了索引之后其他 SQL 也要用 这个索引,其他SQL慢死了,要优化的SQL又快.遇到这种问题咋搞? 一般遇到这种问题还是很少的.处理的方法很多. ...

  6. C# json 转 xml 字符串

    本文告诉大家如何将 json 转 xml 或将 xml 转 json 字符串 首先需要安装 Newtonsoft.Json 库,打开 VisualStudio 2019 新建一个 dotnet cor ...

  7. H3C 查看设备路由表

  8. java 面试题之银行业务系统

    1.需求 模拟实现银行业务调度系统逻辑,具体需求如下: 银行内有6个业务窗口,1 - 4号窗口为普通窗口,5号窗口为快速窗口,6号窗口为VIP窗口. 有三种对应类型的客户:VIP客户,普通客户,快速客 ...

  9. P1035 台阶问题二

    题目描述 有 \(N\) 级的台阶,你一开始在底部,每次可以向上迈最多 \(K\) 级台阶(最少 \(1\) 级),问到达第 \(N\) 级台阶有多少种不同方式. 输入格式 两个正整数 \(N, K( ...

  10. HTTP请求各参数详解

    HTTP Request的Header信息 1.HTTP请求方式 如下表: GET 向Web服务器请求一个文件 POST 向Web服务器发送数据让Web服务器进行处理 PUT 向Web服务器发送数据并 ...