你的 Java 对象占用了多少内存

news2024/12/28 18:54:02

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在本文中,我们将讨论 JVM 如何在内存中存储对象:它们的对齐方式。 对象表示是理解 JVM 底层机制的重要主题,它提供了有助于应用程序调优的见解。

这里,我们主要关注填充和对齐,而不是 JVM 如何在内存中表示对象。要获取有关内存布局的更多信息,请查看这篇文章。

对象对齐

操作系统出于缓存、性能原因和硬件效率的原因使用对齐。**尽管 JVM 是底层操作系统的抽象,但在内部,出于相同的原因,它应该以类似的方式处理对齐。 **

对象对齐在 JVM 上是可配置的。 我们可以使用 -XX:ObjectAlignmentInBytes 提供自定义值。 对齐应该是 2 的幂,并且在 64 位架构上不能超过 4 个字节。

内存消耗

同时,padding 是不含任何有用信息的内存,并且根据对齐大小,padding 大小可能会有所不同。假设我们有以下对象:

public class SimpleObject {
    public int i;
}

我们按照32位系统4字节对齐的组件来计算一下:

空对象的大小 = Mark Word + Klass Pointer + Padding + Instance fields + Padding

在这里插入图片描述

           图 1:32 位架构上具有 4 字节对齐的简单 int 持有者

当对象自然对齐到 4 个字节时,JVM 会忽略填充。

让我们对具有 8 字节对齐和 4 字节(压缩)指针的 64 位架构进行类似的计算:

在这里插入图片描述

                         图2:64 位架构上具有 8 字节对齐的简单int持有者

在这种情况下,对象未对齐,需要额外的八个填充字节。 因此,填充将占用对象大小的三分之一。虽然这听起来像是一个巨大的浪费,但它只对小对象有意义,并且填充大小不能大于对齐。

同时,这意味着64位架构上的以下类不会占用任何额外的空间:

public class SimpleObject {
    public int i;
    public bool b;
}

此类将具有以下布局。在大多数情况下,出于性能原因,布尔值占用一个字节:

在这里插入图片描述

                      图3:64 位架构上具有 8 字节对齐的简单int和bool持有者

由于我们使用了之前分配的填充区域,因此对象的大小没有改变。同时,在 32 位系统上,我们会看到另一张图:

在这里插入图片描述

                              图4:32 位架构上具有 8 字节对齐的简单int和bool持有者

添加另一个bool字段会导致对象大小增加四个字节:一个字节用于布尔值本身,三个字节用于填充。

在 64 位系统上,mark word 将占用 8 个字节。 类指针的大小可能因对齐配置、堆大小和压缩指针的使用而有所不同。如果我们关闭压缩指针,我们将获得以下布局:

在这里插入图片描述

*** 图 5:64 位架构上的简单 int 和 bool 持有者,具有 8 字节对齐和未压缩的(8 字节)指针***

由于我们之前使用了填充,对象的大小没有增加。 我们可以想象压缩会对大量引用类型数组产生怎样的影响,例如 Strings

public class Person {
    private String firstName;
    private String lastName;
    private Address address;
    // constructors, getters, setters, etc.
}

在 64 位系统上使用压缩指针时,对象布局将如下所示:

在这里插入图片描述

                   *****图 6:64位架构上的*Person*对象,具有 8 字节对齐和压缩指针*****

然而,如果我们关闭它们,对象的尺寸就会增加:

在这里插入图片描述

               *****图 7:64位架构上的*Person*对象,具有 8 字节对齐和未压缩的指针*****

在这种情况下,未压缩的引用将增加 8 个额外字节。但是,如果我们想象一个引用类型的列表或数组,我们就能明白它对我们的应用程序有何影响。

参考尺寸和性能

这并不意味着 64 位系统会因为消耗更多内存而变慢。标记字可以包含有关对象的更多信息,例如哈希码和与垃圾回收相关的数据,从而避免往返或额外查找。

1. 创建率低

我们首先回顾一下不会产生太多垃圾的基准:

@Benchmark
public void filteringList(NumberFilteringState state, Blackhole blackhole){
    filterList(state.integers, blackhole);
}

filterList方法将大列表中的偶数和奇数分开:

private static void filterList(List<Integer> integers, Blackhole blackhole)
{
    int even = 0;
    int odd = 0;
    for (final Integer integer : integers) {
        if (integer % 2 == 0) {
            even++;
        } else {
            odd++;
        }
    }
    blackhole.consume(even);
    blackhole.consume(odd);
}

我们可以使用不同的对齐大小以及压缩和非压缩指针来比较其性能。然而,我们使用压缩这一事实导致了最大的差异:

对象对齐性能(8 GB 堆)

对象对齐压缩指针 (ops/s)未压缩指针 (ops/s)
8 个字节193.393242.080
16 字节194.309243.021
32 字节194.631242.330

2. 高创建率

现在,让我们使用另一个基准来查看类似的设置。此基准的创建率较高:

@Benchmark
public void creatingList(NumberFilteringState state, Blackhole blackhole) {
    List<Integer> linkedList = createLinkedList();
    blackhole.consume(linkedList);
}

该基准测试使用以下方法创建一个包含一百万个随机整数的 LinkedList

@NotNull
private static LinkedList<Integer> createLinkedList() {
    return new LinkedList<>(ThreadLocalRandom.current()
      .ints(ONE_MILLION)
      .boxed()
      .collect(Collectors.toList()));
}

如果我们分析一下表现,我们就会得到不同的图景:

对象对齐性能(8 GB 堆)

对象对齐压缩指针 (ops/s)未压缩指针 (ops/s)
8 个字节30.35229.026
16 字节30.74728.922
32 字节30.74628.772

与压缩指针的交互

有趣的是,通过增加对齐大小,我们可以减少内存消耗。这是因为我们减少了放置对象的位置数量。这同时导致可以使用压缩指针。

例如,对于具有 16 字节对齐的 64 GB 堆,我们可以使用带压缩的 32 位指针。我们不需要存储地址的最后四位。它类似于 JVM 默认使用的通常压缩的指针,但由于我们更改了对齐方式,因此我们可以进一步压缩它们。

例如,我们可以用 28 位指针引用具有 48 字节偏移量的对象:

在这里插入图片描述

                                图 8:4 位压缩

当使用 16 字节对齐时,四个最低有效位将始终为零,因此我们可以忽略它们并仅存储 28 位。要恢复原始引用,我们只需进行位移位即可恢复它。

结论

了解对象的对齐方式可让我们深入了解 JVM 的内部工作原理。这些知识可能有助于我们更好地理解,并让我们了解性能配置中经常使用的调优背景和不同的 VM 参数。

以上内容翻原文链接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2130494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS 图片廊:打造精美视觉体验

CSS 图片廊:打造精美视觉体验 随着互联网技术的发展,网页设计越来越注重用户体验和视觉效果的呈现。CSS(层叠样式表)作为网页设计的重要工具,能够帮助开发者创建出既美观又实用的图片展示效果。本文将详细介绍如何使用CSS来打造一个精美的图片廊,以提升网页的视觉效果和…

【C++二分查找】2517. 礼盒的最大甜蜜度

本文涉及的基础知识点 C二分查找 贪心&#xff08;决策包容性) LeetCode 2517. 礼盒的最大甜蜜度 给你一个正整数数组 price &#xff0c;其中 price[i] 表示第 i 类糖果的价格&#xff0c;另给你一个正整数 k 。 商店组合 k 类 不同 糖果打包成礼盒出售。礼盒的 甜蜜度 是礼…

RabbitMQ高级篇,进阶内容

强烈建议在看本篇博客之前快速浏览文章&#xff1a;RabbitMQ基础有这一篇就够了 RabbitMQ高级篇 0. 前言1. 发送者的可靠性1.1 生产者重试机制1.2 生产者确认机制1.3 实现生产者确认 2. MQ的可靠性2.1 MQ持久化2.2 LazyQueue 3. 消费者的可靠性3.1 消费者确认机制3.2 失败重试策…

25、Wpf之App资源应用

开发平台&#xff1a;Win10 64位 开发环境&#xff1a;VS2022(64位) Preview .NET Framework&#xff1a;.NET 6 文章目录 一 Resources1.1 Application中定义资源1.2 样式&#xff08;Styles&#xff09;1.3 模板&#xff08;Templates&#xff09;1.4 数据转换器&#xff08;…

微信自动通过好友和自动拉人进群,微加机器人这个功能太好用了

又发现一个好用的功能&#xff0c;之前就想找一个这种工具&#xff0c;现在发现可以利用微加机器人的两个功能来实现&#xff0c;分别是加好友和关键词拉群 首先 微加机器人的专业版 > 功能 > 加好友设置 可以设置一个关键词通过,这样别人加好友的时候只需要输入制定内…

无人机遂行编队飞行中的纯方位无源定位(2022数模国赛B题)

文章目录 论文项目地址 数模国赛前的练手题&#xff0c;实力不够&#xff0c;参考了好多论文才写出来&#xff0c;个人感觉思路应该没什么大问题&#xff0c;供大家参考 论文 项目地址 github&#xff1a;UAVFormationFlight gitee&#xff1a;UAVFormationFlight 项目包含 完…

数据处理脚手架PyODPS入门体验

本文分享了初次使用PyODPS&#xff08;Python版的Open Data Processing Service&#xff09;的心路历程。作者通过实际案例&#xff0c;深入浅出地探讨了PyODPS相较于传统ODPS SQL在数据处理上的灵活性与便捷性&#xff0c;特别是在处理复杂JSON字段统计与多条件筛选方面展现出…

基于verilog的流水线CPU(无中断异常)

突然发现这个还没传&#xff0c;懒得写了&#xff0c;直接把实验报告传上来吧。 流水线CPU实验报告 ​ 本实验最终实现了11条指令&#xff0c;完成了2位控制的分支预测&#xff0c;以及load-use的阻塞&#xff0c;jump的阻塞&#xff0c;beq预测失败的阻塞&#xff0c;还有RA…

《2024中国数据要素产业图谱2.0版》重磅发布

数据猿出品 本次“数据猿2024年度三大媒体策划活动——《2024中国数据要素产业图谱2.0版》”的发布&#xff0c;下一次版本迭代将于2024年12月底发布2024年3.0版&#xff0c;敬请期待&#xff0c;欢迎报名。 大数据产业创新服务媒体 ——聚焦数据 改变商业 随着技术不断革新&a…

C++函数在库中的地址

本文讲述C如何直接调用动态库dll或者so中的函数。 首先我们准备一个被调用库&#xff0c;这个库里面有两个函数&#xff0c;分别是C98 与 C11 下的&#xff0c;名称是run2和run1。 被调用库 相关介绍请看之前的文章《函数指针与库之间的通信讲解》。 //dll_ex_im.h #ifndef…

【通俗理解】二项分布的均值与方差——从成功与失败的概率看分布

【通俗理解】二项分布的均值与方差——从成功与失败的概率看分布 关键词提炼 #二项分布#均值#方差#成功概率#失败概率#伯努利试验 公式解释与案例 二项分布的基本公式 二项分布描述的是在n次独立重复的伯努利试验中&#xff0c;成功次数的概率分布。每次试验的成功概率为p&…

【Android安全】Ubuntu 16.04安装GDB和GEF

1. 安装GDB sudo apt install gdb-multiarch 2. 安装GEF(GDB Enhanced Features) 官网地址&#xff1a;https://github.com/hugsy/gef 2.1 安装2021.10版本 但是在Ubuntu 16.04上&#xff0c;bash -c "$(curl -fsSL https://gef.blah.cat/sh)"等命令不好使&…

如何用 OBProxy 实现 OceanBase 的最佳路由策略

引言 OBProxy&#xff0c;即OceanBase Database Proxy&#xff0c;也简称为ODP&#xff0c;是 OceanBase数据库的专属服务代理。通过应用OBProxy&#xff0c;由后端OceanBase集群的分布式特性所带来的复杂性得以屏蔽&#xff0c;从而使得访问分布式数据库的体验如同访问单机数…

linux上用yolov8训练自己的数据集(pycharm远程连接服务器)

pycharm如何远程连接服务器&#xff0c;看之前的文章 首先去GitHub上下载项目地址&#xff0c;然后下载预训练模型放到项目主目录下 然后下载数据集&#xff0c;我这有个推荐的数据集下载网站&#xff0c;可以直接下载yolov8格式的数据集&#xff08;还支持其他格式的数据集&a…

进程间通信-命名管道

目录 原理 代码 简单通信 回归概念 原理 mkfifo 是 Linux 系统中的一个命令&#xff0c;用于创建命名管道&#xff08;named pipe&#xff09;&#xff0c;也称为 FIFO&#xff08;First In, First Out&#xff09;。命名管道是一种特殊类型的文件&#xff0c;用于进程间通…

从0到1!本地部署一个大语言模型!完整方法!

要想从零开始部署一个**大语言模型&#xff08;LLM&#xff09;**到本地&#xff0c;不仅仅是硬件上安装软件包&#xff0c;还需要对模型选择、优化和应用搭建有一定的理解。下面是一份完整教程&#xff0c;手把手带你走过如何在本地环境中部署LLM。 1. 了解部署需求与硬件准备…

交换机链路聚合

一、概述 通过链路聚合&#xff0c;可以提高链路的可靠性&#xff0c;提升链路带宽。链路具有一般有手工模式和LACP模式。 二、拓扑图 三、实操演练 1、手工模式 手工模式一般用于老旧、低端设备。 缺点&#xff1a; &#xff08;1&#xff09;为了使链路聚合接口正常工作…

brew install node提示:Error: No such keg: /usr/local/Cellar/node

打开本地文件发现Cellar目录下无法生成 node文件&#xff0c;应该是下载时出现问题&#xff0c;重复下载无法解决问题&#xff0c;只能重新安装brew。 步骤1&#xff08;安装 brew&#xff09;&#xff1a; /bin/zsh -c “$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/ra…

打造高效实时数仓,从Hive到OceanBase的经验分享

本文作者&#xff1a;Coolmoon1202&#xff0c;大数据高级工程师&#xff0c;专注于高性能软件架构设计 我们的业务主要围绕出行领域&#xff0c;鉴于初期采用的数据仓库方案面临高延迟、低效率等挑战&#xff0c;我们踏上了探索新数仓解决方案的征途。本文分享了我们在方案筛选…

uniapp离线(本地)打包

安卓离线打包 注意&#xff1a;jdk建议选择1.8 下载Android Studio配置gradle仓库地址 第一步&#xff1a;先下载对应的版本&#xff0c;进行压缩包解压 第二步&#xff1a;在电脑磁盘&#xff08;D盘&#xff09;&#xff0c;创建文件夹存放压缩包并进行解压&#xff0c;并创…