如何计算Java中的HashMap内存使用情况?
在一次采访中,我被要求计算内存使用量,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位引用),但是序列化格式始终相同。
例如
在Sun /
Oracle的JVM中,一个Integer可以为标头占用16个字节,为数字取4个字节,并填充4个字节(对象在内存中为8字节对齐),总共为24个字节。但是,如果序列化一个Integer,则占用81个字节,序列化两个整数,则占用91个字节。也就是说,第一个Integer的大小被放大,第二个Integer小于内存中使用的大小。
字符串是一个更为复杂的示例。在Sun / Oracle
JVM中,它包含3个int
值和一个char[]
引用。因此,您可能会假设它使用16字节的标头加上int
s的3 *
4字节,的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更复杂,因为即使不是全部,很多String都可以重用,可能是String文字。您所说的“尺寸”取决于其使用方式。即该结构将单独使用多少内存?如果丢弃该结构,将释放多少?如果复制结构,将使用多少内存?这些问题可以有不同的答案。
如果您可以确定可能的保守大小足够小,则确切大小无关紧要。保守的情况可能是您从头开始构造每个String和条目。(我只说一个可能,因为HashMap即使为空也可以容纳10亿个条目。具有单个字符的字符串可以是具有20亿个字符的String的子字符串)
您可以执行System.gc(),获取可用内存,创建对象,执行另一个System.gc()并查看可用内存减少了多少。您可能需要多次创建对象并取平均值。重复此练习很多次,但是可以给您一个不错的主意。
(顺便说一句,虽然System.gc()只是一个提示,但默认情况下,每次,Sun / Oracle JVM都会执行完整GC)
以上是 如何计算Java中的HashMap内存使用情况? 的全部内容, 来源链接: utcz.com/qa/403000.html