所以我正在阅读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内部的内容纯粹是学术上的兴趣:)
答案 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是很难的。
记忆是可重复使用的,但你的时间不是。