首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么Android/Java分析器堆转储显示5个独立的对象和大约7倍的数组开销?

为什么Android/Java分析器堆转储显示5个独立的对象和大约7倍的数组开销?
EN

Stack Overflow用户
提问于 2020-11-14 04:56:01
回答 1查看 340关注 0票数 0

我想知道并测试Android/Java上对象的内存分配,发现堆上发生了一些奇怪的事情,嗯,也许这是正常的。

这是我所做并找到的;有一个txt数据文件,文件大小为850kb,26220行,每行30个字符。我通过inputstream获取所有行,并将它们添加到数组列表中。然后我在Android Studio profiler上转储heap,正如你在截图上看到的那样,heap dump看起来就像是单独计算所有相关对象,然后将它们相加,使得内存大小比实际文本数据大7倍。通常情况下,应用程序堆的总保留大小为2.8MB,创建数组列表后,保留大小约为9MB,因此对于0.85MB的文本数据,它的内存大小为6.2MB。这种行为在Android/Java中是完全正常的,还是profiler出了问题?为什么Java要为对象、数组列表、字符串、byte[]分配那么多的内存,而不是直接创建一个指向或包装数据的数组列表对象呢?提前感谢所有人。

更新

这次我从Android Studio的内存分析器直方图中截取了另一个屏幕截图,而不是堆转储。有趣的是,它显示了预期的内存消耗,或者至少在直方图上没有异常,这与误导性/令人困惑的堆转储不同。正如你在屏幕截图上看到的,在创建arraylist之前,应用程序消耗的总内存是34.5MB,Java内存(应该是堆)是5.2MB。从850KB原始文本文件创建arraylist后,总内存变为37MB,Java为7.1MB,总内存为2.5MB,堆内存为1.9MB。

看起来Android Studio的堆转储上的保留大小信息是误导性的,应该忽略Andreas的建议。

EN

回答 1

Stack Overflow用户

发布于 2020-11-14 05:50:58

你看错了。

我不明白为什么他们把“保留大小”加起来,因为它是一个完全无用的值。

在本例中,我们有一个包含26220个String对象的ArrayList<String>

  • ,这意味着我们有1个ArrayList,所以525个分配中只有1个是我们的。浅的大小是浅的(ArrayList)= 10500 / 525 = 20字节。

  • An ArrayList引用了一个Object[],所以这661个分配中只有一个是我们的。浅的大小取决于数组的大小,但假设它是16字节的开销+每个元素4字节,因此浅(Object[])= 16 +4* 26220 = 104896字节。

  • 数组元素引用了26220个String对象,因此这39896个分配中的26220属于我们。浅的大小是638336 / 39896 = 16字节/ String,所以浅(字符串)= 26220 * 16 = 419520字节。

  • String引用了一个byte[],因此这40407个分配中的26220属于我们。浅层大小取决于数组大小,但假设平均大小为每行30个字符,即每个数组30个字节,这意味着它是16字节开销+ 30字节= 46字节,向上舍入到8的倍数表示48字节,因此48 * 26220 = 1258560字节。不知道为什么它只显示965588字节,但让我们就这样说,所以浅(byte[])= 965588字节。

保留大小是浅层大小+引用的任何内容的保留大小:

代码语言:javascript
复制
retained(byte[]) = shallow(byte[]) // byte[] doesn't reference anything
                 = 965588 bytes

retained(String) = shallow(String) + retained(byte[])
                 = shallow(String) + shallow(byte[])
                 = 419520 + 965588 = 1385108 bytes

retained(Object[]) = shallow(Object[]) + retained(String)
                   = shallow(Object[]) + shallow(String) + shallow(byte[])
                   = 104896 + 419520 + 965588 = 1490004 bytes

retained(ArrayList) = shallow(ArrayList) + retained(Object[])
                    = shallow(ArrayList) + shallow(Object[]) + shallow(String) + shallow(byte[])
                    = 20 + 104896 + 419520 + 965588 = 1490024 bytes

现在,“保留大小”的总和是可笑的,因为如果我们将这4个值相加,我们最终会计算byte[]的965588字节4次,得到965588 + 1385108 + 1490004 + 1490024 = 5330724字节,这是没有任何用处的。请忽略求和的“保留大小”值,因为它完全没有意义。

ArrayList使用1490024字节的内存,而不是6.2MB。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64827927

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档