我在接受采访时被要求计算HashMap
的内存使用量,以及如果你有200万个项目它将消耗多少估计内存。
例如:
Map <String,List<String>> mp=new HashMap <String,List<String>>();
映射是这样的。
key value
----- ---------------------------
abc ['hello','how']
abz ['hello','how','are','you']
我如何估计Java中这个HashMap对象的内存使用情况?
简短的回答
为了找出对象的大小,我会使用一个分析器。例如,在YourKit中,您可以搜索对象,然后让它计算其深度。如果对象是独立的并且对象是保守的大小,这将让您充分了解将使用多少内存。
狡辩
如果物体的一部分在其他结构中重复使用,例如字符串文字,你不会通过丢弃它来释放这么多内存。事实上,丢弃对HashMap的一个引用可能根本不会释放任何内存。
序列化怎么样?
序列化对象是获得估计的一种方法,但由于序列化开销和编码在内存和字节流方面不同,因此它可能会大量关闭。使用了多少内存取决于JVM(以及它是否使用32/64位引用),但序列化格式始终相同。
EG
在Sun / Oracle的JVM中,整数可以占用16个字节用于标头,4个字节用于数字和4个字节填充(对象在内存中是8字节对齐),总共24个字节。但是,如果序列化一个整数,则需要81个字节,串行两个整数,它们需要91个字节。即,第一个整数的大小膨胀,第二个整数小于内存中使用的整数。
字符串是一个更复杂的例子。在Sun / Oracle JVM中,它包含3个int
值和一个char[]
引用。所以你可以假设它使用16字节头加上3 * 4字节用于int
s,4字节用于char[]
,16字节用于char[]
,然后每个字符两个字节,对齐到8字节边界...
什么标志可以改变大小?
如果您有64位引用,则char[]
引用长度为8个字节,从而产生4个字节的填充。如果您有64位JVM,则可以使用+XX:+UseCompressedOops
来使用32位引用。 (所以单看JVM位大小并不能告诉你它的引用大小)
如果你有-XX:+UseCompressedStrings
,JVM将尽可能使用byte []而不是char数组。这可能会略微减慢您的应用程序速度,但可以显着提高您的内存消耗当使用byte []时,消耗的内存为每个字符1个字节。 ;)注意:对于4字符串,如示例所示,由于8字节边界,使用的大小相同。
“大小”是什么意思?
正如已经指出的那样,HashMap和List更复杂,因为很多(如果不是全部)可以重用Strings,可能是String文字。你所说的“大小”取决于它的使用方式。即该结构单独使用多少内存?如果结构被丢弃,将释放多少?如果复制结构,将使用多少内存?这些问题可以有不同的答案。
没有探查器你能做什么?
如果你可以确定可能的保守尺寸,足够小,确切的尺寸无关紧要。保守的情况很可能是从头开始构造每个String和条目的地方。 (我只说可能因为HashMap可以容纳10亿个条目,即使它是空的。带有单个字符串的字符串可以是具有20亿个字符的字符串的子字符串)
您可以执行System.gc(),获取空闲内存,创建对象,执行另一个System.gc()并查看可用内存减少了多少。您可能需要多次创建对象并取平均值。多次重复这个练习,但它可以给你一个公平的想法。
(顺便说一句,虽然System.gc()只是一个提示,但Sun / Oracle JVM默认情况下每次都会执行Full GC)
我认为应该澄清这个问题,因为HashMap的大小和HashMap的大小以及HashMap包含的对象之间存在差异。
如果考虑HashMap的大小,在您提供的示例中,HashMap存储对String“aby”的一个引用和对List的一个引用。因此列表中的多个元素无关紧要。只有对列表的引用存储在值中。
在32位JVM中,在一个Map条目中,“aby”引用有4个字节,List引用有4个字节,Map条目的“hashcode”int属性为4个字节,“next”属性为4个字节地图条目。
您还添加了4 *(X-1)字节引用,其中“X”是HashMap在调用构造函数new HashMap<String,List<String>>()
时创建的空桶数。根据http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html,它应该是16。
还有loadFactor,modCount,threshold和size都是原始int类型(16个字节)和header(8bytes)。
所以最后,你上面的HashMap的大小将是4 + 4 + 1 +(4 * 15)+ 16 + 8 = 93字节
这是基于HashMap拥有的数据的近似值。我想也许访谈者有兴趣看看你是否知道HashMap的工作方式(例如,默认构造函数创建和16个桶的数组用于Map条目,事实是存储在HashMap中的对象的大小不影响HashMap大小,因为它只存储引用)。
HashMap被广泛使用,在某些情况下,应该值得使用具有初始容量和负载因子的构造函数。
如果不知道所有字符串是什么,以及每个列表中有多少项,或者不知道字符串是否都是唯一引用,则事先无法知道。
确切知道的唯一方法是将整个事物序列化为字节数组(或临时文件)并确切地查看字节数。