如何填满一个HashMap?

时间:2020-04-16 19:28:50   收藏:0   阅读:53

如何填满一个HashMap?

step_1 : 计算所需内存

在64位JVM情况下,对象markword占8个字节,指向类的指针占8个字节。

|------------------------------------------------------------------------------|--------------------|
|                                  Mark Word (64 bits)                         |       State        |
|------------------------------------------------------------------------------|--------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 |       Normal       |
|------------------------------------------------------------------------------|--------------------|
| thread:54 |       epoch:2        | unused:1 | age:4 | biased_lock:1 | lock:2 |       Biased       |
|------------------------------------------------------------------------------|--------------------|
|                       ptr_to_lock_record:62                         | lock:2 | Lightweight Locked |
|------------------------------------------------------------------------------|--------------------|
|                     ptr_to_heavyweight_monitor:62                   | lock:2 | Heavyweight Locked |
|------------------------------------------------------------------------------|--------------------|
|                                                                     | lock:2 |    Marked for GC   |
|------------------------------------------------------------------------------|--------------------|

HashMap的每一个节点结构如下:

 static class Node<K,V> implements Map.Entry<K,V> {
        final int hash; //4个字节
        final K key;    //8个字节
        V value;        //8个字节
        Node<K,V> next; //8个字节
    //以下省略    
 }

综上所述,每一个Node在默认8字节对齐后占48字节。
HashMap规定最多含有2G个Node
2G*48=96G

    /**
     * The maximum capacity, used if a higher value is implicitly specified
     * by either of the constructors with arguments.
     * MUST be a power of two <= 1<<30.
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

若K 为Integer类型,则K 内存占24字节
2G*24=48G

HashMap 中 table 字段如下

    /**
     * The table, initialized on first use, and resized as
     * necessary. When allocated, length is always a power of two.
     * (We also tolerate length zero in some operations to allow
     * bootstrapping mechanics that are currently not needed.)
     */
    transient Node<K,V>[] table;

按照该数组的最大长度(2^31)约等于2G

注:实际上在Hotspot下数组的最大索引为2^31-3

2G*8=16G

综上:填满一个HashMap 至少需要96G+48G+16G=160G内存

step_2 : 测试代码

import java.util.HashMap;

public class TestMaxHashMap {
    public static void main(String[] args) {
        Integer a= 0;

        System.out.println("process:"+Runtime.getRuntime().availableProcessors());
        System.out.println(Runtime.getRuntime().maxMemory()/(1024*1024*1024)+"G");
        long begin=System.currentTimeMillis();
        System.out.println("begin at :"+begin);
        HashMap<Integer,Integer> hashMap=new HashMap<>(Integer.MAX_VALUE);
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            hashMap.put(i,a);
        }
        System.out.println("current size: "+hashMap.size());
        long end=System.currentTimeMillis();
        System.out.println("end at :"+end);
        long expire=end-begin;
        System.out.println("expire "+expire+" mill");

        System.out.println("maxMemory : "+Runtime.getRuntime().maxMemory());
        System.out.println("freeMemory : "+Runtime.getRuntime().freeMemory());
        System.out.println("totalMemory : "+Runtime.getRuntime().totalMemory());

        System.out.println("I will add first ");
        hashMap.put(-10086,a);
        System.out.println("currentSize: "+hashMap.size());
        System.out.println("I will add second ");
        hashMap.put(-10087,a);
        System.out.println("currentSize: "+hashMap.size());
        System.out.println("I will add third ");
        hashMap.put(-10088,a);
        System.out.println("currentSize: "+hashMap.size());
        System.out.println("the project end !");
    }
}


step_3 : 硬件配置

主机为32核256G云服务器
内存:

ubuntu@VM-0-10-ubuntu:~$ free
              total        used        free      shared  buff/cache   available
Mem:      264023320   210517376    52956076        8848      549868    52200720
Swap:             0           0           0

CPU:

ubuntu@VM-0-10-ubuntu:~$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                32
On-line CPU(s) list:   0-31
Thread(s) per core:    1
Core(s) per socket:    32
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 94
Model name:            Intel(R) Xeon(R) Gold 6133 CPU @ 2.50GHz

step_4 : 运行结果

运行结果如下

ubuntu@VM-0-10-ubuntu:~$ java -Xms250g TestMaxHashMap 
process:32
239G
begin at :1587032320457
current size: 2147483647
end at :1587033300316
expire 979859 mill
maxMemory : 257250820096
freeMemory : 93706040008
totalMemory : 257250820096
I will add first 
currentSize: -2147483648
I will add second 
currentSize: -2147483647
I will add third 
currentSize: -2147483646
the project end !

填满大概需要15min
可以看出当超出Integer.MAX_VALUE时 HashMap 并不会抛异常

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!