Java 为Hashtable.put()分配的内存

Java 为Hashtable.put()分配的内存,java,optimization,Java,Optimization,所以我在读Peter Norvig的室内空气品质(不常被问到的问题)时偶然发现: 你可能会惊讶地发现 对象的长度为16字节,即4个字 Sun JDK虚拟机。这会分解为 如下:有一个两个单词的标题, 其中一个单词是指向 对象的类和其他点 添加到实例变量。尽管 对象没有实例变量,Java 仍然为 变量。最后,还有一个问题 “handle”,这是指向 两个单词的标题。孙说, 这种额外的间接性使 垃圾收集更简单。(那里 具有高性能的Lisp和 Smalltalk垃圾收集器 至少在一个月内不要使用额外的关

所以我在读Peter Norvig的室内空气品质(不常被问到的问题)时偶然发现:

你可能会惊讶地发现 对象的长度为16字节,即4个字 Sun JDK虚拟机。这会分解为 如下:有一个两个单词的标题, 其中一个单词是指向 对象的类和其他点 添加到实例变量。尽管 对象没有实例变量,Java 仍然为 变量。最后,还有一个问题 “handle”,这是指向 两个单词的标题。孙说, 这种额外的间接性使 垃圾收集更简单。(那里 具有高性能的Lisp和 Smalltalk垃圾收集器 至少在一个月内不要使用额外的关卡 15年了。我听说过,但没有 确认MicrosoftJVM没有 没有额外级别的 间接的。)

空的新字符串()需要40个字节, 或10个单词:指针的3个单词 开销,实例为3个单词 变量(开始索引、结束索引、, 和字符数组),以及用于 空字符数组。创建一个 现有字符串的子字符串采用 “仅”6个字,因为字符数组 是共享的。放置一个整数键并 将整数值转换为哈希表 64字节(除了四个 在中预先分配的字节 哈希表数组):我让你工作 找出原因

显然我试过了,但我想不出来。下面我只数单词: Hashtable put创建一个Hashtable$Entry:3(开销)+4个变量(我假设3个引用是1个单词+1个int)。我进一步假设他指的是新分配的整数(因此未被Integer类缓存或已存在),其值为2*(3[开销]+1[1整数值])

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

我很清楚,这一切都取决于实际的JVM实现(在64位版本上,结果会有所不同),但我还是不喜欢回答不了的问题:)


编辑:只是想让这更清楚一点:虽然我很清楚更紧凑的结构可以让我们获得一些性能优势,但我同意,一般来说,在这里或那里担心几个字节是浪费时间的。我当然不会因为这里或那里的一些字节开销而停止使用哈希表,就像我不会使用纯字符数组而不是字符串一样(或者开始使用C)。了解Java/JVM内部的更多信息纯粹出于学术兴趣:)

作者似乎假设有3个对象,每个对象的开销为16字节,映射中有2个32位引用。Entry和2 x 1 32位
int
值。这总共是64个字节

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

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

这一切都是非常低效的,这就是为什么您可以使用像TIntIntHashMap这样的类来代替使用原语的类

然而,通常情况下,这并不重要,因为当你把它与你的时间成本相比时,内存是惊人的便宜。如果您在服务器应用程序上工作,并且您的公司每小时的成本约为40美元,那么您需要每分钟节省大约10 MB的内存,以节省所需的内存。(理想情况下,您需要节省更多)每分钟节省10 MB是很困难的


内存是可重用的,但您的时间不是。但由于缓存行为,紧凑型结构可能比大型结构快得多,因此如果在紧密循环中使用Java对象,你仍然在浪费宝贵的时间:你和用户花在等待程序完成上的时间。哦,我甚至不会考虑停止使用HashMap或字符串,因为我可以在这里或那里节省一些字节,尽管我作为学生的空闲时间确实很便宜。可以说那只是一种学术兴趣。是的,我们忽略了分配边界和64位,因为这个条目肯定有几年历史了。但我仍然不知道如何获得64字节-最多我们分配2个新整数和1个哈希表$Entry-哈希表$Entry中的下一个条目不是新分配的,但在我看来只是一个引用。@larsmans,我同意在性能关键型系统中,缓存是一种高级功能。我对大多数系统的印象是,它们的调优不够精细,缓存效果不是一个主要因素。我可能正在工作@Voo,即使你没有得到报酬,你的时间也是有价值的。也许它不值得每小时40美元,也许它每小时只有4美分,但仍然是每分钟10KB。您只考虑对象中的字段,每个对象都有开销。您引用的文本似乎非常旧(因为它提到了Microsoft JVM)。Hashtable的实现在当时可能是不同的。是的,那可能是真的,我试图找到1.3 JDK的源代码,但让我感到困惑的是,这在今天似乎几乎是不可能的。可能是你用3个单词计算,虽然引用中使用了4个单词,但实际上发现了一个古老的1.3jdk,条目类是相同的(除了明显缺少泛型)@对不起,我不明白-我的意思是代码是开放的,我不知道我在哪里漏掉了一个变量?不,我的意思是,在你引用的文本中,它说[…]一个对象需要16个字节,或4个字,而你的计算开销是3个字。对不起,如果我错了,我几个小时前就应该在床上了,现在想不清楚了。