Java 8 hashmap高内存使用率

前端之家收集整理的这篇文章主要介绍了Java 8 hashmap高内存使用率前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我使用hashmap存储QTable来实现强化学习算法.我的hashmap应该存储15000000个条目.当我运行算法时,我看到进程使用的内存超过1000000K.当我计算内存时,我预计它的使用量不会超过530000K.我试着写一个例子,我得到了相同的高内存使用率:
public static void main(String[] args) {
    HashMap map = new HashMap<>(16_000_000,1);
    for(int i = 0; i < 15_000_000; i++){
        map.put(i,i);
    }
}

我的记忆力:

每个入口集都是32个字节
容量为15000000
HashMap实例使用:32 * SIZE 4 * CAPACITY
memory =(15000000 * 32 15000000 * 4)/ 1024 = 527343.75K

我的记忆计算错在哪里?

解决方法

好吧,在最好的情况下,我们假设字长为32位/ 4字节(使用CompressedOops和CompressedClassesPointers).然后,映射条目由两个单词JVM开销(klass指针和标记字),键,值,哈希码和下一个指针组成,总共6个字,换句话说,24个字节.因此,拥有15,000,000个条目实例将消耗360 MB.

此外,还有包含条目的数组. HashMap使用的幂为2的幂,因此对于15,000个条目,数组大小至少为16,777,216,消耗64 MiB.

然后,您有30,000个Integer实例.问题是map.put(i,i)执行两次装箱操作,并且鼓励JVM在装箱时重复使用对象,但不需要这样做,并且在您可能完成的简单程序中不会重复使用在优化器干扰之前.

确切地说,前128个Integer实例被重用,因为对于-128 … 127范围内的值,共享是必需的,但是实现通过在第一次使用时初始化整个缓存来实现,因此对于前128次迭代,它不会创建两个实例,但缓存由256个实例组成,这是该数字的两倍,因此我们最终再次使用30,000个Integer实例. Integer实例至少包含两个JVM特定字和实际int值,它们将产生12个字节,但由于默认对齐,实际消耗的内存将为16个字节,可分为8个字节.

因此,30,000个创建的Integer实例消耗480 MB.

这使得总共360 MB 64 MiB 480 MB,超过900 MB,使得1 GB的堆大小完全合理.

但这就是分析工具的用途.运行你的程序后,我得到了

请注意,此工具仅报告对象的已用大小,即Integer对象的12个字节,而不考虑在查看JVM分配的总内存时将注意到的填充.

猜你在找的Java相关文章