为Hashtable.put()分配的内存

时间:2011-05-28 16:18:47

标签: java optimization

所以我正在阅读Peter Norvig的IAQ(不经常问的问题 - link)并偶然发现了这一点:

  

你可能会惊讶地发现一个   对象需要16个字节或4个字   Sun JDK VM。这打破了   如下:有一个双字标题,   其中一个单词是指向的   对象的类,以及其他要点   到实例变量。即使   Object没有实例变量Java   仍然为...分配一个单词   变量。最后,有一个   “handle”,这是另一个指针   双字标题。孙说   这种额外的间接水平使得   垃圾收集更简单。 (那里   一直是高性能的Lisp和   做的Smalltalk垃圾收集器   至少不要使用额外的等级   15年。我听说但没有   确认了Microsoft JVM   没有额外的水平   间接。)

     

一个空的新String()占用40个字节,   或10个字:3个字的指针   开销,实例的3个单词   变量(起始索引,结束索引,   和字符数组),和4个单词   空char数组。创建一个   现有字符串的子字符串   “只有”6个字,因为char数组   是共享的。放一个整数键和   将整数值转换为Hashtable   64字节(除了四个   预先分配的字节数   Hashtable数组):我会让你工作   为什么。

我很明显地尝试过,但我无法理解。在下面我只算数字: Hashtable put创建一个Hashtable $ Entry:3(开销)+4个变量(我假设3个引用是1个字+ 1个int)。我进一步假设他意味着整数是新分配的(因此不是由Integer类缓存或已经存在),它来到2 *(3 [overhead] + 1 [1 int value])。

所以最后我们最终得到了15个字或60个字节。所以我首先想到的是,作为一个内部类的Entry需要引用它的外部对象,但是它是静态的,因此没有多大意义(确定我们必须存储指向父类的指针,但我会认为信息由VM存储在类头中。

只是空闲的好奇心,我很清楚这一切都取决于实际JVM实现的一点点(在64位版本上结果会有所不同),但我仍然不喜欢我不能解决的问题回答:)

编辑:只是为了让这一点更加清晰:虽然我很清楚更紧凑的结构可以为我们带来一些性能上的好处,但我同意这里通常担心几个字节或者浪费时间。我肯定不会因为这里的几个字节开销而停止使用Hashtable,就像我不会使用普通字符数组而不是字符串(或开始使用C)。学习更多关于Java / JVM内部的内容纯粹是学术上的兴趣:)

1 个答案:

答案 0 :(得分:2)

作者似乎假设有3个对象,每个对象有16个字节的开销,Map.Entry有2个32位引用,2 x 1个32位int值。这将总共64字节

这是有缺陷的,因为Sun / Oracle的JVM仅在8字节边界上分配,因此技术上整数占用20个字节的内存,使用24个字节(8的下一个倍数)

此外,许多JVM现在使用64位引用,因此Map.Entry将使用另外16个字节。

这都非常低效,这就是为什么你可能会使用像TIntIntHashMap这样的类来使用原语。

然而,通常情况并不重要,因为当你将它与你的时间成本进行比较时,内存会出乎意料地便宜。如果您使用服务器应用程序并且您的公司每小时花费约40美元,则需要每分钟节省大约10 MB,以节省尽可能多的内存。 (理想情况下,您需要节省更多费用)每分钟节省10 MB是很难的。

记忆是可重复使用的,但你的时间不是。