JVM之对象
几乎所有对象都是在堆中分配内存的,这次来讲讲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之对象的更多相关文章
- JVM中对象的创建过程
JVM中对象的创建过程如以下流程图中所示: 对其主要步骤进行详细阐述: 为新生对象分配内存: 内存的分配方式: 指针碰撞:假设Java堆中内存是绝对规整的,所有用过的内存放在一边,空闲的内存在另一边, ...
- JVM中对象的回收过程
当我们的程序开启运行之后就,就会在我们的java堆中不断的产生新的对象,而这是需要占用我们的存储空间的,因为创建一个新的对象需要分配对应的内存空间,显然我的内存空间是固定有限的,所以我们需要对没有 ...
- Java虚拟机笔记(五):JVM中对象的分代
为什么要分代 为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用, ...
- jvm回收对象
jvm在判断对象死亡之前需要判断对象是否可到达,方法有引用计数算法和可达性分析算法,jvm采用的是后者.首先来了解一下这两种算法. 引用计数算法: 算法定义 为每个对象增加一个字段记录被引用的次数,并 ...
- JVM——深入分析对象的内存布局
概述 一个对象本身的内在结构需要一种描述方式,这个描述信息是以字节码的方法存储在方法区中的.Class本身就是一个对象,都以KB为单位,如果new Integer()为了表示一个数据就占用KB级别的内 ...
- JVM与对象初始化
一个对象从无到有的过程 A a = new A() 1.JVM遇到new指令就会去堆内存分配一块内存空间,内存的大小在编译期间就可以确定 2.接着调用A的构造函数,这里构造的时候会沿着继承树逆流而上, ...
- JVM之对象分配:栈上分配 & TLAB分配
1. Java对象分配流程 2. 栈上分配 2.1 本质:Java虚拟机提供的一项优化技术 2.2 基本思想: 将线程私有的对象打散分配在栈上 2.3 优点: 2.3.1 可以在函数调用结束后自行销毁 ...
- JVM(3)对象A和B循环引用,最后会不会不被GC回收?-------关于Java的GC机制
①首先说一下,GC里边在JVM其中是使用的ROOT算法,ROOT算法,什么称作为ROOT呢,就是说类的静态成员,静态成员就是static修饰的那种,是"根"的一个,根还包含方法中的 ...
- @JVM中对象的引用类型
JVM中有四种引用类型:强引用.软引用.弱引用.虚引用 强引用(Stong Reference):是指在程序代码中普遍存在的,类似:Object obj = new Object()这类的引用,只 ...
- JVM(二) 对象存活判断和垃圾回收算法
对象的创建 概述 下面简要介绍创建对象的几个重要步骤 : 检查能否在常量池定位到一个类的符号引用,并检查这个符号代表的类是否已被加载,解析和初始化过.如果没有则执行类加载的操作.(即是说对象的引用放在 ...
随机推荐
- laravel 授权使用gate门类
第一:先注册 第二:使用方式三种 路由中:Route::group(['middleware'=>'can:system'],function() {}) 模板中:@can("syst ...
- js创建对象的三种方式和js工厂模式创建对象
文章地址: https://www.cnblogs.com/sandraryan/ 创建对象 创建对象的三种方式 构造函数 ,是一种特殊的方法.主要用来在创建对象时初始化对象 1. 调用系统的构造函数 ...
- php页面最大执行时间 set_time_limit函数不起作用
作者: default|标签:PHP set_time_limit 执行时间|2017-3-21 15:03 set_time_limit 不生效或者无效解决方法 <?php globa ...
- 下推栈实现(c++编程思想 p136)
1 头文件Stack.h #ifndef STACK_H #define STACK_H struct Stack { struct Link { void* data; Link* next; vo ...
- centos7.0 可以访问HTML文件,不能访问PHP文件,因为php-fpm没有扩展包
解决方法 :https://blog.csdn.net/ityang_/article/details/53980190 nginx调用PHP有sock方式和端口方式 1.确认nginx已经调用了ph ...
- es6—变量的解构赋值
数组的解构赋值 ]]]]]]] = []}} = {}} = {}})]: first]: last} = arr} = {}) {}))}))}) {}))}))].]]]])})] }}} = { ...
- Java内存溢出java.lang.OutOfMemoryError: PermGen space
今天把以前的一个项目部署在tomcat,启动没问题.因为用到了webservice,当调用webservice中的方法时一直报内存溢出异常 Exception in thread "http ...
- vue中的时间修饰符stop,self
stop阻止自身以外的冒泡 self只会阻止自身冒泡
- vue-learning:2 - template - directive
指令 directive 在上一节我们知道,VUE的template模板通过VUE指令API实现与页面的视图层联系.所以本节将聚集在实现视图层交互的VUE指令系统directive的基础使用. 我们先 ...
- codeforces 1183F 离散化枚举 约数定理
codeforces1183F 有技巧的暴力 传送门:https://codeforces.com/contest/1183/problem/F 题意: 给你n个数,要你从中选出最多三个数,使得三个数 ...