Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 集合中的内存消耗_Java_Memory Management_Collections - Fatal编程技术网

Java 集合中的内存消耗

Java 集合中的内存消耗,java,memory-management,collections,Java,Memory Management,Collections,嗨,最近在一次采访中,有人问我有一个Hashmap、一个ArrayList和一个Hashset。它们各自包含相同的10个用户定义对象(例如:Employee类对象)。哪个会消耗更多堆空间?为什么 我给出的答案是Hashmap,因为它存储了两个键值对。但是Hashset也在内部使用hashmap来存储值 有人能给我一个合理的答案吗 是否有任何工具或eclipse插件我可以用来检查自己 谢谢 如果您同时计算容器所需的内存和“10个用户定义对象”所需的内存,那么您是正确的 HashMap将占用更多空间

嗨,最近在一次采访中,有人问我有一个Hashmap、一个ArrayList和一个Hashset。它们各自包含相同的10个用户定义对象(例如:Employee类对象)。哪个会消耗更多堆空间?为什么

我给出的答案是Hashmap,因为它存储了两个键值对。但是Hashset也在内部使用hashmap来存储值

  • 有人能给我一个合理的答案吗
  • 是否有任何工具或eclipse插件我可以用来检查自己

  • 谢谢

    如果您同时计算容器所需的内存和“10个用户定义对象”所需的内存,那么您是正确的

    HashMap
    将占用更多空间

    尽管
    HashSet
    HashMap
    支持,但它在所有条目中存储的值都是对同一虚拟实例的引用

    因此,
    HashSet
    需要10个键引用+10个值引用+10个元素+1个虚拟实例

    另一方面,
    HashMap
    需要10个键引用+10个值引用+10个键实例+10个值实例(假设“10个用户定义对象”存储为值)

    当然,为了更准确,还必须计算包含
    HashMap
    s bucket的数组的大小,但是
    HashMap
    HashSet
    中的大小是相同的,因为它们包含相同数量的元素

    请注意,正如JB Nizet所评论的,如果
    HashMap
    的键是“10个用户定义对象”的属性,“10个键实例”不需要额外的内存(因为它们已经存在),因此
    HashMap
    HashSet
    都需要相同的内存量来存储10个对象,由于
    HashSet
    实际上需要更多的内存,因为它包含对
    HashMap
    的引用


    ArrayList
    应该比
    HashSet
    HashMap
    占用更少的内存,因为
    ArrayList
    的备份数组的默认初始长度为10(足以存储10个对象),而
    HashMap
    的存储桶数组的默认初始长度为16(假设我们使用默认负载系数0.75,也足以存储10个对象)。

    我发现这非常有趣,虽然我同意Eran的观点,但需要适当的证明。我正在使用

    在本例中,我创建了一个
    Employee
    ,其中包含两个字段
    String name
    int age

    让我们看看发生了什么:

    List<Employee> list = new ArrayList<>();
    list.add(new Employee(22, "a"));
    
    System.out.println(GraphLayout.parseInstance(list).totalSize()); //152 bytes
    
    出于示例的考虑,我接下来将添加2名员工,并缩短关于规模的解释:

    HashMap<Employee, Integer> map = new HashMap<>();
    map.put(new Employee(22, "a"), 100);
    map.put(new Employee(23, "b"), 200);
    
    System.out.println(GraphLayout.parseInstance(map).toFootprint()); 
    
    总大小为368字节。现在,让我们将它们放入一个
    哈希集

    HashSet<Employee> set = new HashSet<>();
    set.add(new Employee(22, "a"));
    set.add(new Employee(23, "b"));
    
    System.out.println(GraphLayout.parseInstance(set).totalSize()); // 368 bytes
    
    HashSet=newhashset();
    增加(新雇员(22,“a”);
    增加(新雇员(23,“b”);
    System.out.println(GraphLayout.parseInstance(set.totalSize());//368字节
    


    您可以看到一个
    HashSet
    和一个
    HashMap
    对于这个特定场景具有相同的大小。如果您添加超过12个条目(默认情况下,
    HashMap
    重新调整大小),事情会变得更加棘手并且可能会将它的bucket从
    LinkedNode
    s更改为
    TreeNode
    s,这两者之间存在差异。
    Node
    是32字节,而
    TreeNode
    是56字节。

    您的答案是正确的。任何文本编辑器都允许查看JDK附带的HashMap和HashSet的代码。@JBNizet但HashSet也存储为键值对(虽然本例中的值是常量)。所以它应该只有hashmap。对吗?因为我可以有任何大于hashset默认当前值的值。我不明白“它应该只有hashmap”或“我可以有任何大于默认当前值的值”是什么意思。我的意思是假设在散列映射中有一个字符串作为值,它占用300字节。现在在散列集中存在一个伪值(让它的大小为100字节)。因此,每次呈现的大小都是恒定的,但散列映射中的值大小可能会有所不同。我希望这一次我很清楚。考虑到他们只说映射中存储了员工,可以假设(我确实这么做)键是该员工的字段(例如,他的姓名或ID)。在这种情况下,没有额外的10个键实例,HashMap和HashSet消耗相同的内存量(实际上,对于HashSet来说要多一点,因为它需要对其备份HashMap的引用)。@JBNizet如果键是“用户定义对象”的属性那么你是对的。好的,因为问题是关于十个元素的,我根本不希望有任何容量增加操作。
    ArrayList的默认容量是十,所以所有元素都适合,
    HashMap
    的默认容量是
    16
    ,负载因子是
    0.75
    ,所以它最多可以接受十二个元素当然,
    16
    仍然大于
    10
    ,因此
    HashMap
    /
    HashSet
    在这种情况下具有更大的容量(在其他情况下,
    HashMap
    在需要时将容量加倍,而
    ArrayList
    使用系数1.5)@Eran我喜欢这个答案,但我真的很想证明,所以我给你的添加了一个小的扩充…很好的分析!但是,你得到的
    HashSet
    HashMap
    的368字节结果不是巧合吗?毕竟,你的
    HashMap
    示例还有两个
    Integer
    实例,但另一方面,
     HashSet
    示例具有额外的
    私有瞬态HashMap;
    引用(以及同时具有
    HashSet
    HashMap
    实例的开销)。如果放置/添加10个条目/元素,会得到相同的结果吗?@Eran一个好的捕获-我选择了这些值
      COUNT       AVG       SUM   DESCRIPTION
         2        24        48   [C
         1        80        80   [Ljava.util.HashMap$Node;
         2        16        32   java.lang.Integer
         2        24        48   java.lang.String
         1        48        48   java.util.HashMap
         2        32        64   java.util.HashMap$Node
         2        24        48   org.erabii.tenelemdiff.Test$Employee
        12                 368   (total)
    
    HashSet<Employee> set = new HashSet<>();
    set.add(new Employee(22, "a"));
    set.add(new Employee(23, "b"));
    
    System.out.println(GraphLayout.parseInstance(set).totalSize()); // 368 bytes