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(二) 对象存活判断和垃圾回收算法
对象的创建 概述 下面简要介绍创建对象的几个重要步骤 : 检查能否在常量池定位到一个类的符号引用,并检查这个符号代表的类是否已被加载,解析和初始化过.如果没有则执行类加载的操作.(即是说对象的引用放在 ...
随机推荐
- C# POST 表单发送文件
表单提交协议规定:要先将 HTTP 要求的 Content-Type 设为 multipart/form-data,而且要设定一个 boundary 参数,这个参数是由应用程序自行产生,它会用来识别每 ...
- vue4——把输入框的内容添加到页面(简单留言板)
文章地址:https://www.cnblogs.com/sandraryan/ vue最最最简单的demo(记得引入) 实例化一个vue,绑定#app的元素,要渲染的数组arr作为data. 把ar ...
- Python--day72--Cookie和Session内容回顾
1. Cookie是什么 保存在浏览器端的键值对 为什么要有Cookie? 因为HTTP请求是无状态的 Cookie的原理? 服务端可以在返回响应的时候 做手脚 在浏览器上写入键值对(Cookie) ...
- H3C PPP MP简介
- jekyll 添加 Valine 评论
本文告诉大家如何在自己搭建的静态博客添加 Valine 评论.在这前,我基本都是使用 多说,但是多说gg啦,所以就在找一个可以替换的评论 本来 Disqus是很好的,但是在国内很难打开,所以我就需要一 ...
- 常用mime.types
以下是从nginx配置文件mime.types中提取出的最常用的文件格式, 整理了下, 方便查看 类型 文件格式 default_type application/octet-stream - tex ...
- 2019-8-31-C#-await-高级用法
title author date CreateTime categories C# await 高级用法 lindexi 2019-08-31 16:55:58 +0800 2018-2-13 17 ...
- 土旦:移动端 Vue+Vant 的Uploader 实现 :上传、压缩、旋转图片
面向百度开发 html <van-uploader :after-read="onRead" accept="image/*"> <img s ...
- Blazor 服务端组件 Render, RenderFragment ,RenderTreeBuilder, CascadingValue/CascadingParameter
一.组件 支撑Blazor的是微软的两大成熟技术,Razor模板和SignalR,两者的交汇点就是组件.通常,我们从ComponentBase派生的类型,或者创建的.razor 文件,就可以称作组件. ...
- VIM 用正则表达式,非贪婪匹配,匹配竖杠,竖线, 匹配中文,中文正则,倒数第二列, 匹配任意一个字符 :
VIM 用正则表达式 批量替换文本,多行删除,复制,移动 在VIM中 用正则表达式 批量替换文本,多行删除,复制,移动 :n1,n2 m n3 移动n1-n2行(包括n1,n2)到n3行之下: ...