为什么android/java profiler堆转储会显示5个单独的对象和大约7倍的arraylist开销?

wnavrhmk  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(333)

我想在android/java上测试object的内存分配,发现heap上发生了一些奇怪的事情,也许这很正常。
这就是我所做的和发现的;有一个txt数据文件,文件大小为850kb,26220行,每行30个字符。我通过inputstream获取所有行,并将它们添加到arraylist。然后我在android studio profiler上转储heap,正如您在屏幕截图上看到的,heap dump看起来像是分别计算所有相关对象,然后将它们全部相加,使内存大小比实际文本数据大7倍。通常appheap的总保留大小在创建arraylist之前是2.8mb,在创建arraylist之后大约是9mb,因此对于0.85mb的文本数据,它的内存大小是6.2mb。这种行为在android/java中是完全正常的还是profiler有什么问题?为什么java要为object、arraylist、string、byte[]单独分配这么多内存,而不是直接用指针或 Package 数据创建arraylist对象?提前谢谢大家。

更新
这次我从androidstudio的内存分析器直方图中截取了另一个屏幕截图,而不是从堆转储中截取的。有趣的是,它显示的内存消耗与预期一致,或者至少在这个直方图上没有异常,不像误导性/混乱的堆转储。正如您在屏幕截图上看到的,在创建arraylist之前,应用程序消耗的总内存是34.5mb,java内存(应该是heap)是5.2mb。从850kb的原始文本文件创建arraylist后,总内存变为37mb,Java7.1mb使总内存变为2.5mb,堆内存变为1.9mb。
androidstudio堆转储中保留的大小信息似乎有误导性,应该像andreas建议的那样被忽略。

kd3sttzy

kd3sttzy1#

你看错了。
我无法理解他们为什么要总结“保留大小”,因为这是一个完全无用的值。
在这种情况下,我们有一个 ArrayList<String> 与26220 String 物体:
也就是说我们有1个 ArrayList 所以在525个分配中只有一个是我们的。浅值大小是浅值(arraylist)=10500/525=20字节。
ArrayList 参考文献 Object[] 因此,在这661笔拨款中,只有1笔是我们的。浅层大小取决于数组大小,但是假设它是16字节开销+每个元素4字节,所以浅层(object[])=16+426220=104896字节。
数组元素引用26220 String 所以39896次分配中有26220次属于我们。浅层大小为638336/39896=16字节/秒 String ,所以浅(字符串)=26220
16=419520字节。 String 参考文献a byte[] 所以40407个分配中有26220个属于我们。浅表大小取决于数组大小,但让我们考虑平均大小为每行30个字符,即每个数组30个字节,这意味着它的开销是16字节+30字节=46字节,向上舍入到8的倍数意味着48字节,因此48*26220=1258560字节。不知道为什么它只显示965588字节,但让我们继续,所以浅(byte[])=965588字节。
保留大小是浅尺寸+任何引用的保留大小:

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个值相加,我们最终会计算出数据的965588字节 byte[] 4次,得到965588+1385108+1490004+1490024=5330724字节,这没有任何用处。请忽略“保留大小”的总和,因为它完全没有意义。
这个 ArrayList 使用1490024字节的内存,而不是6.2mb。

相关问题