- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我试图了解 Java 中对象的内存占用量是多少。我读了this和其他关于 Java 中的对象和内存的文档。
但是,当我使用 sizeof Java library或 visualvm,我得到两个不同的结果,其中没有一个符合我根据之前的引用 (http://www.javamex.com) 所期望的结果。
对于我的测试,我使用的是 Java SE 7 Developer Preview
在 64-bits Mac
与 java.sizeof 0.2.1
和 visualvm 1.3.5
.
我有三个类,TestObject
, TestObject2
, TestObject3
.
public class TestObject
{
}
public class TestObject2 extends TestObject
{
int a = 3;
}
public class TestObject3 extends TestObject2
{
int b = 4;
int c = 5;
}
我的主要类(class):
public class memoryTester
{
public static void main(String[] args) throws Throwable
{
TestObject object1 = new TestObject();
TestObject2 object2 = new TestObject2();
TestObject3 object3 = new TestObject3();
int sum = object2.a + object3.b + object3.c;
System.out.println(sum);
SizeOf.turnOnDebug();
System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object1)));
System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object2)));
System.out.println(SizeOf.humanReadable(SizeOf.deepSizeOf(object3)));
}
}
使用 java.SizeOf() 我得到:
{ test.TestObject
} size = 16.0b
16.0b
{ test.TestObject2
a = 3
} size = 16.0b
16.0b
{ test.TestObject3
b = 4
c = 5
} size = 24.0b
24.0b
使用 visualvm 我有:
this (Java frame) TestObject #1 16
this (Java frame) TestObject2 #1 20
this (Java frame) TestObject3 #1 28
根据我在 Internet 上阅读的文档,因为我是 64 位的,所以我应该有一个 16 字节的对象头,对于 TestObject
来说没问题.
那么 TestObject2
我应该为整数字段添加 4 个字节,给出 20 个字节,我应该再次添加 4 个字节的填充,给 TestObject2
的总大小为 24 个字节.我错了吗?
对 TestObject3
继续这样做,我必须为两个应该提供 32 个字节的整数字段再添加 8 个字节。
VisualVm 似乎忽略了填充,而 java.sizeOf 似乎错过了 4 个字节,就好像包含在对象头中一样。我可以用 4 个 boolean 值替换一个整数,结果相同。
问题:
为什么这两个工具给出不同的结果?
我们应该有填充吗?
我还在某处读到(我没有找到链接),在一个类和它的子类之间可能有一些填充,对吗?在这种情况下,继承的类树可能会有一些内存开销?
最后,是否有一些 Java 规范/文档详细说明了 Java 正在做什么?
感谢您的帮助。
更新:
为了回答 utapyngo 的评论,为了获得 visualvm 中对象的大小,我创建了一个 heapdump,然后在“类”部分中,我检查了“实例”列之后的“大小”列。每种对象的实例数(如果为 1)。
为了回答 Nathaniel Ford 的评论,我初始化了每个字段,然后在我的 main 方法中对它们进行了简单的求和以利用它们。结果并没有改变。
最佳答案
是的,可能会发生填充。堆栈上的对象也可以完全优化。只有 JVM 知道任何时间点的确切大小。由于这种从 Java 语言中近似大小的技术都倾向于不同意,但是附加到 JVM 的工具往往是最准确的。我知道在 Java 中实现 sizeOf 的三种主要技术是:
这些技术都不准确。
如果您在 Oracle JVM 上运行,则在 v1.5 或之后。然后有一种方法可以直接从 Java 运行时使用的 C 结构中读取对象的大小。对于生产来说不是一个好主意,如果弄错了,你可能会导致 JVM 崩溃。但是,如果您想尝试一下,这里有一篇博文可能会让您觉得有趣:http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/
关于 Java 实际操作的文档,即 JVM 特定、版本特定和可能的配置特定。每个实现都可以自由地以不同的方式处理对象。即使在完全优化对象的范围内,例如,没有从堆栈中传递出来的对象也是空闲的,不会被分配到堆上。一些 JVM 甚至可以设法将对象完全保留在 CPU 寄存器中。这里不是你的情况,但我将它作为一个例子说明为什么获取 Java 对象的真实大小很棘手。
因此,最好将任何 sizeOf 值拿来用少许盐获得,并将其仅视为“指导”测量值。
关于Java 对象内存占用 - Visualvm 和 java.sizeOf 测量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15490561/
使用 VisaulVM,我想将其作为数据获取,而不应用图像处理算法......我该怎么做?我认为这不会来自快照。 我不确定 VisualVM 和 jVisualVM 有何不同,命名肯定令人困惑,但我正
我正在从 VisualVM 1.3.2 迁移到 1.3.3,并希望将我设置的所有远程服务器和应用程序迁移到这个新安装。 我查看了 %HOMEPATH%\Application Data.visualv
我的查询结果有数百万行。我已经修改了visualvm.conf -J-DOQLController.limitResults=1000000 目前,作为一种解决方法,我运行查询,然后将结果复制并粘贴到
我正在运行 JDK 1.8.0_66 JVisualVM 实用程序,并希望使用 MBeans 浏览器来监视我的 Coherence 应用程序。 根据Oracle教程,我必须首先安装MBeans插件。所
我的查询结果有数百万行。我已经修改了visualvm.conf -J-DOQLController.limitResults=1000000 目前,作为一种解决方法,我运行查询,然后将结果复制并粘贴到
我正在使用 VisualVM 来监控许多 JAVA 应用程序,我想安装一些在这个应用程序中可用的插件。不幸的是,“可用插件”选项对我自己不起作用,因为我相信我可能被阻止了通过公司代理。 我可以如何以及
我在使用“Java VisualVM”时遇到了一些麻烦,它似乎是 Oracle 品牌的,而且关于我正在运行版本 1.6.0_51 的页面声明的丑陋之处。 特别是让我失望的一件事是,我一直在运行这个非常
如果我使用适用于 Java8 的 AdoptOpenJDK HotSpot 构建,我可以使用 VisualVM 监控应用程序。 如果我使用 OpenJ9 版本,VisualVM 会显示错误“无法检测到
我可以附加到 surefire 进程,但尝试分析它显示采样: CPU sampling: Not available. Failed to create JMX connection to targe
在我的项目中,我们使用一个小型的 Java 分析工具。它显示了我们的应用程序加载到内存中的所有对象,并实时反射(reflect)了对象的变化。我们主要用它来调试。 我的问题是:它如何运作?外部应用程序
我在 visualvm v1.3.8 中找到所需的对象: filter(heap.objects("java.lang.String"), "/hibernate\\.ejb\\.naming/(it
我正在尝试为 VisualVM 安装一些插件,但它一直卡在下面的屏幕上 - 告诉我“请等待安装程序发现插件依赖项”。我运行的是 Ubuntu 12.04。当我尝试从“可用插件”列表中安装它们时,以及当
我正在尝试为 VisualVM 安装一些插件,但它一直卡在下面的屏幕上 - 告诉我“请等待安装程序发现插件依赖项”。我正在运行 Ubuntu 12.04。当我尝试从“可用插件”列表安装它们时,以及当我
我正在使用 VisualVM(内置于 JDK1.6)来分析我的 Java 应用程序以查找内存泄漏。我正在使用堆转储和探查器(内存监视器)这两个 VisualVM 功能...有一些不一致之处,我无法理解
我正在使用 VisualVM 来分析 javafx 8 应用程序,该应用程序执行一些绘图操作,并且使用的内存比我想要的多得多。它似乎没有泄漏,但由于某种原因,我的总堆永远不会减少,即使当我选择不同的文
正在监视 Java 应用程序的线程锁定情况, 在 visualvm 的监控标签下, Activity 线程:112Live Peak:126守护线程:99开始总数:135,742 这是什么意思?我觉得
这似乎是一个荒谬的问题。在 google 上搜索 VisualVM 会得到很多信息,包括据称很容易连接到正在运行的 JVM 和监视器。 嗯,事实并非如此。我不知道如何将 VisualVM 连接到我正在
我正在尝试分析一个应用程序,我有很多类型为 sim.core.EndPoint$2 的实例 当我检查这些实例时,我确认它们不是 sim.core.EndPoint 类型,它们似乎是一个 EndPoin
今天我对得到的 Visual VM 分析结果感到困惑。 我有以下简单的Java方法: public class Encoder { ... private BitString encode(I
我已将tomcat(已分配8GB堆内存)连接到visualvm。在 VisualVM 中,在“采样器”->“内存”选项卡下,分配的总内存显示为 17GB(18470717672 字节)。但只分配了8G
我是一名优秀的程序员,十分优秀!