如何计算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字节的标头加上ints的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

回到顶部