如今,有大胆的工程师在为Oracle工作。 昨天尝试确定Heisenbug时,我得出了这个结论。 不足为奇,当我尝试找到解决方案时,该错误似乎消失了。 几个小时后,将问题归结为JDK7更新之间的细微差别,该错误的“ Heisen”部分被删除。
但是回到勇敢的主张。 为了理解我所描述的情况,我将其提取到一个非常简单的测试代码段中供您尝试:
class OOM {public static void main(String[] args) {java.util.Map m = new java.util.HashMap(10_000_000);}
}
现在,当我使用JDK7u40或更高版本在64位Mac OS X上启动课程时:
my:tmp user$ /path-to/jdk1.7.0_40/bin/java -Xmx96m OOM
my:tmp user$
您会看到命令提示符返回,并且JVM成功完成了其工作。 现在,使用JDKu25或更早版本启动相同的类:
my:tmp user$ /path-to/jdk1.7.0_25/bin/java -Xmx96m OOM
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.HashMap.(HashMap.java:283)at java.util.HashMap.(HashMap.java:297)at OOM.main(OOM.java:3)
您会看到不同的结果。 使用100M条目初始化HashMap无法在我们的约100m堆中分配足够的资源,并且JVM退出并抛出OutOfMemoryError 。
在这种情况下, HashMap的来源显然是第一大嫌疑人。 的确,当您将JDK 7u25的源代码与下一个发行版(名为u40,为命名感到敬佩!)进行比较时,您会看到很大的不同。 Hashmap(initialCapacity,loadFactor)构造函数现在将忽略您构造初始大小等于initialCapacity的HashMap的意愿。 取而代之的是,您看到仅当在地图上调用第一个put()方法时,基础数组才被延迟分配。
一个看似非常合理的变化– JVM在各个方面本质上都是懒惰的,所以为什么不将大型数据结构的分配推迟到迫切需要这种分配时才进行。 因此从这个意义上讲,这是一个很好的选择。
从某种意义上说,某个特定的应用程序正在通过反射执行技巧,并直接访问Map实现的内部结构,也许不是。 但是,同样,不应该绕过API并开始变得聪明,所以也许特定的开发人员现在更加相信每个新发现的概念都不适用于任何地方。
如果您是API开发人员,您是否会自己进行更改? 我不敢相信自己会有胆量,因为要知道实施过程中各种怪异的方面,大约有成千上万的应用程序在那儿。 但是我确实对JDK内的合理变更投了赞成票,并且可以肯定地说这是好的。
翻译自: https://www.javacodegeeks.com/2013/11/would-you-dare-to-change-hashmap-implementation.html