技术标签: Java
【JVM系列4】new Object()到底占用几个字节,看完这篇就彻底明白了
package com.zwx.jvm;
public class HeapMemory {
private Object obj1 = new Object();
public static void main(String[] args) {
Object obj2 = new Object();
}
}
上面的代码中,obj1 和obj2在内存中有什么区别?
答: 这个obj1是存在方法区的,而new会创建一个对象实例,对象实例是存储在堆内的,于是就有了下面这幅图(方法区指向堆):
而obj2 是属于方法内的局部变量,存储在Java虚拟机栈内的栈帧中的局部变量表内,这就是经典的栈指向堆:
疑问: 堆内的示例对象是如何知道自己属于哪个Class,也就是说这个实例是如何知道自己所对应的类元信息的呢?
对象内存中可以分为三块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding),以64位操作系统为例(未开启指针压缩的情况) Java对象布局如下图所示:
上图中的对齐填充不是一定有的,如果对象头和实例数据加起来刚好是8字节的倍数,那么就不需要对齐填充。
Object obj=new Object()占用多少字节?
以64位操作系统为例,new Object()占用大小分为两种情况:
未开启指针压缩
占用大小为:8(Mark Word)+8(Class Pointer)=16字节
开启了指针压缩(默认是开启的)
开启指针压缩后,Class Pointer会被压缩为4字节,最终大小为:
8(Mark Word)+4(Class Pointer)+4(对齐填充)=16字节
我们来验证一下。
首先引入一个pom依赖:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
新建一个简单的demo:
package com.zwx.jvm;
import org.openjdk.jol.info.ClassLayout;
public class HeapMemory {
public static void main(String[] args) {
Object obj = new Object();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
输出结果如下:
最后的结果是16字节,没有问题,这是因为默认开启了指针压缩,那我们现在把指针压缩关闭之后再去试试。
-XX:+UseCompressedOops 开启指针压缩
-XX:-UseCompressedOops 关闭指针压缩
再次运行,得到如下结果:
可以看到,这时候已经没有了对齐填充部分了,但是占用大小还是16位。
下面我们再来演示一下如果一个对象中带有属性之后的大小。
新建一个类,内部只有一个byte属性:
package com.zwx.jvm;
public class MyItem {
byte i = 0;
}
开启指针压缩,占用16字节:
关闭指针压缩,占用24字节:
这个时候就能看出来开启了指针压缩的优势了,如果不断创建大量对象,指针压缩对性能还是有一定优化的。
目前最主流的访问对象方式有两种:句柄访问和直接指针访问。
使用句柄访问的话,Java虚拟机会在堆内划分出一块内存来存储句柄池,那么对象当中存储的就是句柄地址,然后句柄池中才会存储对象实例数据和对象类型数据地址。
直接指针访问的话对象中就会直接存储对象类型数据。
句柄访问和直接指针访问对比
使用句柄访问的时候,会多了一次指针定位,但是他也有一个好处就是,假如一个对象被移动(地址改变了),那么只需要改变句柄池的指向就可以了,不需要修改reference对象内的指向,而如果使用直接指针访问,就还需要到局部变量表内修改reference指向。
Java堆内存中按照分代年龄来划分,分为Young区和Old区,对象分配首先会到Young区,达到一定分代年龄(-XX:MaxTenuringThreshold可以设置大小,默认为15)就会进入Old区(注意:如果一个对象太大,那么就会直接进入Old区)。
之所以会这么划分是因为如果整个堆只有一个区的话,那么垃圾回收的时候每次都需要把堆内所有对象都扫描一遍,浪费性能。而其实大部分Java对象的生命周期都是很短的,一旦一个对象回收很多次都回收不掉,可以认为下一次垃圾回收的时候可能也回收不掉,所以Young区和Old区的垃圾回收可以分开进行,只有当Young区在进行垃圾回收之后还是没有腾出空间,那么再去触发Old区的垃圾回收。
触发了GC(垃圾回收),对用户线程是有影响的,因为GC过程中为了确保对象引用不会不断变化,需要停止所有用户线程,Sun把这个事件称之为:Stop the World(STW)。
明明有空间,但是因为空间不连续,导致对象申请内存失败,导致触发GC了,那么如何解决这种问题呢?
解决的思路就是把Young区的对象按顺序放好,所以就产生了一个方法,把Young区再次划分一下,分为2个区:Eden区和Survivor区。
大部分对象都是生命周期极短的,基本一次垃圾回收就可以把Eden区大部分对象回收掉(这个前提是经过测试总结得到的)。
触发GC的时候Survivor区也会一起回收,并不是说单独只触发Eden区,但是这样问题又来了,Eden区是保证空间基本连续了,但是Survivor区又可能产生空间碎片,导致不连续了,所以就又把Survivor区给一分为二了:
文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib
文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang
文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些
文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器
文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距
文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器
文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn
文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios
文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql
文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...
文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120
文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数