草庐IT

java - Java中32位和64位系统中对象大小的差异

coder 2023-06-04 原文

我碰到一个面试问题:

class Test {
    int a ; 
    int b;
    char c;
}

此类需要多少内存对象以及为什么在以下对象上实现:

a)32位计算机

b)64位计算机

我得到的答案是:
For 32-bit: 4+4+2+8 = 18 bytes
For 64-bit: 4+4+2+16 = 26 bytes

由于分配了一些额外的内存,除了对象的正常大小外,在32位系统中为8字节,在64位系统中为16字节。

您能否对此声明提供一些解释。

附注:我也想分享我从其他来源得到的答案(不能依靠,想验证):

在32位pc对象中,比其数据成员所定义的实际obj大小多占用8个字节....在64位pc对象中,其数据成员所定义的实际obj大小比其实际对象大.....问题出现的原因...据我所知,其背后的原因是:::在32位pc中,JVM保留了前8个字节,用于引用类定义,对齐,父类(super class)和子类的空间等。 。对于64位,它为这些对象保留16个字节。.有一个公式可以计算对象在创建时需要多少堆空间,并将其计算为.....。 。浅堆大小= [对类定义的引用] +父类(super class)字段的空间+实例字段的空间+ [对齐]

您如何计算对象“自身”需要多少内存?显然有一个公式可以解决:

浅堆大小= [对类定义的引用] +父类(super class)字段的空间+实例字段的空间+ [对齐]

似乎不太有用,是吗?让我们尝试使用以下示例代码来应用公式:
class X {
  int a;
  byte b;
  java.lang.Integer c = new java.lang.Integer();
}
class Y extends X {
  java.util.List d;
  java.util.Date e;
}

现在,我们努力回答的问题是–一个Y实例需要多少浅堆大小?让我们开始计算它,假设我们使用的是32位x86体系结构:

作为起点– Y是X的子类,因此它的大小包括父类(super class)中的“某物”。因此,在计算Y的大小之前,我们先考虑计算X的浅大小。

跳到X上的计算中,前8个字节用于引用其类定义。该引用始终存在于所有Java对象中,并且被JVM用来定义以下状态的内存布局。它还具有三个实例变量–一个int,一个Integer和一个字节。这些实例变量需要堆,如下所示:

一个字节就是应该的。内存中有1个字节。
我们的32位架构中的int需要4个字节。
对整数的引用也需要4个字节。请注意,在计算保留堆时,我们还应考虑包装到Integer对象中的原语的大小,但是在此处计算浅堆时,我们在计算中仅使用4个字节的引用大小。
那么-是吗? X的浅堆=从引用到类定义的8个字节+ 1个字节(该字节)+ 4个字节(int)+ 4个字节(对Integer的引用)= 17个字节?实际上–不。现在起作用的是对齐(也称为填充)。这意味着JVM以8字节的倍数分配内存,因此如果创建X的实例,我们将分配24字节而不是17字节。

如果您可以在这里关注我们,那很好,但是现在我们尝试使事情变得更加复杂。我们不是在创建X的实例,而是在创建Y的实例。这意味着–我们可以从引用中减去8个字节到类定义和对齐方式。乍一看可能不太明显,但是–您是否注意到,在计算X的浅大小时,我们没有考虑到它也扩展了java.lang.Object,因为即使您未在其中明确声明它,所有类也会这样做。您的源代码?我们不必考虑父类(super class)的 header 大小,因为JVM足够聪明,可以从类定义本身进行检查,而不必一直将其复制到对象 header 中。

对齐方式也一样–创建对象时,您只能对齐一次,而不是在父类(super class)/子类定义的边界处对齐。因此,可以肯定地说,当创建X的子类时,您只会从实例变量继承9个字节。

最后,我们可以跳到初始任务并开始计算Y的大小。正如我们所看到的,我们已经在父类(super class)字段中丢失了9个字节。让我们看看当我们实际构造一个Y实例时将添加什么。

Y的标题引用了其类定义,占用了8个字节。与以前的相同。
日期是对对象的引用。 4字节。简单的。
该列表是对集合的引用。同样是4个字节。不重要的。
因此,除了父类(super class)中的9个字节外,我们还有8个字节的头空间,2×4个字节的数据来自两个引用(列表和日期)。 Y实例的总浅层大小为25个字节,对齐为32个字节。

最佳答案

取决于JVM。对于HotSpot JVM,正确的答案是:

  • 32位JVM:24字节 = align8(4字节mark_word + 4字节类引用+ 4 + 4 + 2字节字段数据)
  • 64位JVM -XX:+ UseCompressedOops:24字节 = align8(8字节mark_word + 4字节类引用+ 4 + 4 + 2字节字段数据)
  • 64位JVM -XX:-UseCompressedOops:32字节 = align8(8字节mark_word + 8字节类引用+ 4 + 4 + 2字节字段数据)
  • 关于java - Java中32位和64位系统中对象大小的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24836854/

    有关java - Java中32位和64位系统中对象大小的差异的更多相关文章

    1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

      总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

    2. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

      我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

    3. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

      在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

    4. ruby - 将差异补丁应用于字符串/文件 - 2

      对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

    5. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

      我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

    6. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

      我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

    7. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

      我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

    8. Ruby 写入和读取对象到文件 - 2

      好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

    9. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

      如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

    10. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

      我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

    随机推荐