在一次采访中,我被要求计算内存使用量,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监视以下系统信息: 当前的CPU使用率*(百分比) 可用内存 (可用/总计) 可用磁盘空间(可用/总) 请注意,我的意思是整个系统可用的整体内存,而不仅仅是JVM。 我正在寻找一种不依赖于我自己的调用外部程序或使用JNI的代码的跨平台解决方案(Linux,Mac和Windows)。尽管这些是可行的选择,但如果有人已经有了更好的解决方案,我宁愿自己不要维护特定于操作系统的代
问题内容: 如果我有: 和 通常 一个数组 如何同时考虑引用变量来计算实际内存使用量? 问题答案: 如果您想要一个准确的答案,那就不能了。至少不是以任何简单的方式。该主题说明更多。 Bragaadeesh和Bakkal的答案的麻烦在于它们忽略了开销。每个数组还存储诸如它具有的维数,它有多长时间以及垃圾收集器使用的一些东西之类的东西。 对于简单的估算,应该使用其他答案中的计算并加上100-200字节
问题内容: 我需要在Java中检查服务器的CPU和内存使用情况,有人知道怎么做吗? 问题答案: 如果你正在专门寻找JVM中的内存: 但是,这些仅应作为估计…
问题内容: 扩展基类时,Java中的内存使用情况如何。 子类是否包含基类的实例(具有其自身的开销和全部开销),还是仅具有其自身的16字节的开销? 那么,更具体地说,Bar实例的内存使用量是多少? 是吗 要不就 问题答案: 没有双重开销。 Java将采用该类,超类,计算所有字段所需的空间,并为一个实例分配所需的空间。 仅从内存的角度来看,根本不存在超类的概念,有Foo的实例仅需要一个int的内存,而
问题内容: 最近,我对算法产生了兴趣,并通过编写一个简单的实现,然后以各种方式对其进行了优化来开始探索它们。 我已经熟悉了用于分析运行时的标准Python模块(对于大多数事情,我发现IPython中的timeit magic函数就足够了),但是我也对内存使用感兴趣,因此我也可以探索这些折衷方案(例如,缓存先前计算的值与根据需要重新计算它们的表的成本)。是否有一个模块可以为我配置给定功能的内存使用情
问题内容: 是否有一个准则来估计a消耗的内存量? 寻找类似于这些准则的估计内存使用情况的东西。 问题答案: 如果您查看源代码中的字段,则有: 的评论说 用于存储规范的字符串表示形式(如果已计算)。 假设您不调用,它将保留为零字节。因此是(8 + 4 + 4)= 16个字节+ 。 本身是4 + 4 + 4 + 4 + 4 = 20字节+ 。 20 + 16总共提供了36个字节加上大小,该大小始终是表