首页 / 知识
关于内存:在Java中,确定对象大小的最佳方法是什么?
2023-04-14 17:23:00

In Java, what is the best way to determine the size of an object?例如,假设我有一个应用程序,可以用成堆的数据行读取csv文件。我根据数据类型给用户一个行数的摘要,但是我要确保我不读取太多的数据行并导致 现在,我有代码说可以读取多达32000行,但我也希望代码说可以读取尽可能多的行,直到我使用32MB的内存。也许这是一个不同的问题,但我还是想知道。 您可以使用java.lang.instrument包 编译该类并将其放入jar中:
在您的
使用GetObjectSize:
调用:
您应该使用jol,它是作为OpenJDK项目的一部分开发的工具。
要获得原语、引用和数组元素的大小,请使用
您可以使用
您可以使用
如果您使用
"(something else)"条目描述堆中不属于此对象图的其他对象。 最好的jol文档是jol存储库中的jol示例。这些示例演示了常见的jol操作,并展示了如何使用jol分析VM和垃圾收集器内部。 几年前,JavaWork发表了一篇文章,讨论了复合和潜在嵌套Java对象的大小,它们基本上是通过在爪哇中创建一个siZeFor()实现的。该方法基本上建立在其他实验中,人们在实验中识别原语和典型Java对象的大小,然后将该知识应用于递归地遍历对象图以统计总大小的方法。 它总是比本机C实现稍差一些,这仅仅是因为类背后发生了一些事情,但它应该是一个很好的指示器。 或者,一个名为sizeof的sourceforge项目,它提供了一个带有sizeof()实现的java5库。 P.S.不要使用序列化方法,序列化对象的大小和它在活动时消耗的内存量之间没有相关性。 首先,"对象的大小"在Java中不是一个定义良好的概念。你可以指的是对象本身,只有它的成员,对象和它所指的所有对象(参考图)。您可以是指内存大小或磁盘大小。并且允许JVM优化字符串之类的东西。 因此,唯一正确的方法是使用一个好的探查器(我使用yourkit)询问JVM,这可能不是您想要的。 但是,从上面的描述来看,似乎每一行都是自包含的,并且没有大的依赖树,因此序列化方法可能是大多数JVM的一个很好的近似方法。最简单的方法如下:
请记住,如果有具有公共引用的对象,这将不会给出正确的结果,而且序列化的大小并不总是与内存中的大小匹配,但这是一个很好的近似值。如果您将bytearrayOutputstream大小初始化为一个合理的值,代码将更高效。 我偶然发现了一个Java类"jdk.nashorn.internal.ir.debug.objectsizecalculator",已经在jdk中,它很容易使用,而且对于确定一个物体的大小很有用。
结果:
如果您只想知道在您的JVM中使用了多少内存,有多少是空闲的,您可以尝试这样做:
编辑:我认为这可能会有帮助,因为问题的作者还说,他希望有处理"在我使用32MB内存之前,尽可能多地读取行"的逻辑。 当我在Twitter工作时,我写了一个实用程序来计算深度对象的大小。它考虑了不同的内存模型(32位,压缩OOP,64位),填充,子类填充,在循环数据结构和数组上正确工作。你可以编译这个.java文件,它没有外部依赖关系: https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/objectsize/objectsizecalculator.java 许多其他答案都提供了较浅的大小——例如,没有任何键或值的哈希图的大小,这不太可能是您想要的。 jamm项目使用上面的java.lang.instrumentation包,但会遍历树,因此可以给您提供深层内存使用。
https://github.com/jbelis/jamm 你必须使用反射来移动物体。像你这样小心:
@Jodonnell:我喜欢您的解决方案的简单性,但是许多对象是不可序列化的(因此这会引发异常),字段可以是临时的,对象可以覆盖标准方法。 您必须使用一个工具来测量它,或者手工估计它,这取决于您使用的JVM。 每个对象都有一些固定的开销。它是特定于JVM的,但我通常估计有40个字节。然后你必须看看班上的成员。对象引用是32位(64位)JVM中的4(8)个字节。基本类型包括:
数组遵循相同的规则;也就是说,它是一个对象引用,因此在对象中需要4(或8)个字节,然后它的长度乘以它的元素的大小。 尝试通过对 还有内存测量工具(以前在Google代码,现在在Github上),它很简单,并在商业友好的Apache2.0许可证下发布,在类似的问题中讨论过。 如果你想测量内存字节消耗,它也需要命令行参数到Java解释器,但是在我使用它的场景中,它看起来很好。 EDCOX1的1个类提供了一个获得Java对象大小的好方法,但是它要求您定义一个EDCOX1,2个,并用Java代理运行程序。当您不需要任何代理,然后必须为应用程序提供一个虚拟的JAR代理时,这是非常无聊的。 所以我从
不必处理插入等问题,如果不需要知道对象的字节大小,可以使用以下方法:
通过这种方式,您可以前后读取使用过的内存,并在获取使用过的内存之前调用GC,您可以将"噪声"降低到几乎为0。 为了获得更可靠的结果,您可以运行作业n次,然后将使用的内存除以n,得到一次运行需要多少内存。更重要的是,你可以把整件事做更多次,并得出平均值。 这里有一个实用程序,我使用一些链接的例子来处理32位、64位和64位的压缩OOP。它使用 它使用EDCOX1×1来获得一个本地指针的大小和EDCOX1(2)对Java引用的大小的影响。 它使用已知类的字段偏移量计算对象的基本大小。
如果你要求的是方法调用,那么就没有方法调用。通过一点研究,我想你可以自己写。一个特定的实例有一个固定的大小,这个大小是由引用的数量和原语值加上实例簿记数据得出的。您只需浏览对象图。行类型的变化越小,就越容易。 如果这太慢或只是比它的价值更多的麻烦,总是有很好的老式的排数规则的拇指。 我曾经写过一个快速测试来评估:
一般的概念是分配对象和测量空闲堆空间中的变化。密钥是
这就是我们所期望的,给定对齐行为和可能的堆块头开销。 这里的仪器方法在公认的答案中是最准确的。我描述的方法是准确的,但仅在没有其他线程创建/丢弃对象的受控条件下。 只需使用Java Visual VM即可。 它拥有分析和调试内存问题所需的一切。 它还有一个OQL(对象查询语言)控制台,允许您做许多有用的事情,其中一个是 我的答案是基于尼克提供的代码。该代码测量被序列化对象占用的总字节数。所以这实际上是测量序列化的东西+普通的对象内存占用(只是序列化,例如
我已经用基本类型、字符串和一些普通类测试了这个解决方案。也可能没有涵盖的案例。 更新:修改示例以支持数组对象的内存足迹计算。 您可以生成一个堆转储(例如,使用JMAP),然后分析输出以查找对象大小。这是一个离线解决方案,但您可以检查浅尺寸和深尺寸等。 假设我声明一个名为
为了查看分配给此类活动实例的内存量:
这个答案与对象大小无关,但当您使用数组来容纳对象时,它将为对象分配多少内存大小。 因此,数组、列表或映射所有这些集合将不会真正存储对象(仅在基元时需要实际的对象内存大小),它将只存储这些对象的引用。 现在是江户十一〔五〕。
基元
物体
我的意思是说所有的对象引用只需要4个字节的内存。它可以是字符串引用或双对象引用,但取决于对象创建,所需的内存将有所不同。 例如,如果我为下面的类
因此,在创建对象/引用数组时,它的所有内容都将被空引用占据。我们知道每个引用需要4个字节。 最后,下面代码的内存分配是20字节。 referenceMemoryTest ref1=new referenceMemoryTest();(4(ref1)+12=16字节)referenceMemoryTest ref2=ref1;(4(ref2)+16=20字节)
由于对象的创建,大小会增加JVM的内存使用量,这通常是对象的大小。 对于jsonObject,下面的代码可以帮助您。
返回字节大小 我用jsonarray对象检查了它,将它写到一个文件中。它给出了物体的大小。 我怀疑你是否想通过编程来实现它,除非你只想实现一次,并将其存储起来以备将来使用。这是一件昂贵的事情。在Java中没有siZOFF()运算符,即使存在,也只计算引用到其他对象的成本和基元的大小。 一种方法是将其序列化为文件,并查看文件的大小,如下所示:
当然,这假定每个对象都是不同的,并且不包含对其他任何对象的非瞬时引用。 另一种策略是对每个对象进行反射并检查其成员,然后将大小相加(布尔值字节=1字节,短字符=2字节等),沿着成员层次结构向下工作。但是,这是乏味和昂贵的,并且最终做的和序列化策略一样。 |
最新内容
相关内容
linux读取码值命令?
linux读取码值命令?,系统,工作,地址,证书,命令,工具,档案,文件,设计,信息,基本linux命令1、linux系统常用操作命令如下:ls:全拼list,功能是列出目linux无效对象的命令?
linux无效对象的命令?,软件,系统,单位,网络,管理,术语,检测,电脑,环境,风险,linux疑问:普通用户的ifconfig命令无法执行,如何解决?建议这个操linux数据库查找命令?
linux数据库查找命令?,位置,名称,状态,服务,软件,信息,系统,命令,名字,密码,在linux中如何用命令查找文件在哪使用查找命令 “find”命令允许linux数据库同步命令?
linux数据库同步命令?,信息,系统,汽车,车辆,服务,工作,通信,一致,分析,数据,DB2数据库在linux操作系统的指令有哪些?1、linux系统常用操作命令linux建立数据库命令?
linux建立数据库命令?,软件,系统,工作,数据,密码,工具,数据库,一致,网络,服务,linux中在shell中怎么创建一个数据库1、以下的文章主要讲述的是linux的查看内存命令?
linux的查看内存命令?,情况,系统,信息,电脑,状态,工具,内存,命令,数据,总量,Linux下怎么查看内存使用情况和CPU利用率?在电脑中进入Linux操作linux命令进数据库?
linux命令进数据库?,地址,系统,名字,服务,密码,命令,读法,数据库,操作系统,主机,linux系统mysql数据库怎么进入数据库首先确保linux下mysql安linux下内存调整命令?
linux下内存调整命令?,系统,情况,地址,工具,总量,总额,管理,内存,机制,内核,正确理解linux运行内存过高的问题以及free命令使用命令free -m来linux清空表数据命令?
linux清空表数据命令?,系统,数据,软件,名称,不了,命令,文件,电脑,地址,位置,Linux删除文件的命令?1、linux 删除文件指令:输入rd盘符名:\文件夹linux拷贝数据命令?
linux拷贝数据命令?,系统,地址,文件,数据,命令,目录,服务,基本知识,项目,密码,linux复制命令?1、在Linux中,用于复制文件和目录的命令是cp。cplinux内存大小命令?
linux内存大小命令?,系统,情况,电脑,信息,工具,状态,命令,内存,环境,分析,Linux命令行查看内存1、cat /proc/meminfo查看linux系统内存大小的linux内存命令大全?
linux内存命令大全?,地址,系统,信息,工作,命令,情况,代码,分析,数据,工具,[Linux]gdb查看内存区命令1、命令缩写是q,退出gdb。gdb调试运行程序