Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/308.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
与ArrayList相比,Java HashMap的内存开销_Java_Arraylist_Hashmap_Memory Management - Fatal编程技术网

与ArrayList相比,Java HashMap的内存开销

与ArrayList相比,Java HashMap的内存开销,java,arraylist,hashmap,memory-management,Java,Arraylist,Hashmap,Memory Management,我想知道与ArrayList相比,java HashMap的内存开销是多少 更新: 我想提高搜索一大包(600多万)相同对象的特定值的速度 因此,我考虑使用一个或多个HashMap,而不是使用ArrayList。但是我想知道HashMap的开销是多少 据我所知,密钥不是存储的,只是密钥的散列,所以它应该类似于对象散列的大小+一个指针 但是使用什么哈希函数呢?是它还是另一个?最简单的方法是查看源代码并以这种方式进行计算。然而,你实际上是在比较苹果和橙子——列表和地图在概念上是完全不同的。很少会根据

我想知道与ArrayList相比,java HashMap的内存开销是多少

更新:

我想提高搜索一大包(600多万)相同对象的特定值的速度

因此,我考虑使用一个或多个HashMap,而不是使用ArrayList。但是我想知道HashMap的开销是多少

据我所知,密钥不是存储的,只是密钥的散列,所以它应该类似于对象散列的大小+一个指针


但是使用什么哈希函数呢?是它还是另一个?

最简单的方法是查看源代码并以这种方式进行计算。然而,你实际上是在比较苹果和橙子——列表和地图在概念上是完全不同的。很少会根据内存使用情况在它们之间进行选择


这个问题背后的背景是什么?

我不知道确切的数字,但哈希图要重得多。比较两者,ArrayList的内部表示是不言而喻的,但是HashMaps保留了条目对象(Entry),这会增加内存消耗


它没有那么大,但它更大。可视化这一点的一个好方法是使用动态探查器,例如,它允许您查看所有堆分配。非常好。

正如乔恩·斯基特所说,这些是完全不同的结构。映射(如HashMap)是从一个值到另一个值的映射,也就是说,在键->值的关系中,有一个键映射到一个值。该键被散列,并被放置在一个数组中以便快速查找

另一方面,列表是具有顺序的元素集合-ArrayList碰巧使用数组作为后端存储机制,但这与此无关。每个索引元素都是列表中的单个元素

编辑:根据您的评论,我添加了以下信息:


密钥存储在hashmap中。这是因为哈希不能保证对任何两个不同的元素都是唯一的。因此,在哈希冲突的情况下必须存储密钥。如果您只是想查看一组元素中是否存在一个元素,请使用set(该元素的标准实现是HashSet)。如果顺序很重要,但需要快速查找,请使用LinkedHashSet,因为它保持插入元素的顺序。两者的查找时间均为O(1),但LinkedHashSet的插入时间稍长。仅当您实际从一个值映射到另一个值时才使用映射-如果您只是有一组唯一的对象,请使用一个集合,如果您有有序的对象,请使用列表。

Hashmaps尝试保持一个加载因子(通常75%已满),您可以将hashmap视为一个稀疏填充的数组列表。直接比较大小的问题是,映射的负载因子会随着数据的大小而增长。另一方面,ArrayList通过将其内部数组大小增加一倍来满足需要。对于相对较小的大小,它们是可比较的,但是当您将越来越多的数据打包到映射中时,需要大量空引用才能保持哈希性能

在任何一种情况下,我都建议在开始添加之前启动预期大小的数据。这将为实现提供一个更好的初始设置,并且在这两种情况下都可能消耗更少的资源

更新:


根据您的最新问题进行检查。这是一个整洁的小工具,由一些谷歌人编写,用于执行与您描述的类似的操作。它也很快。允许聚类、过滤、搜索等。我也没有答案,但是快速的谷歌搜索在Java中提供了一个功能,可能会有所帮助

Runtime.getRuntime().freemory()

因此,我建议您使用相同的数据填充HashMap和ArrayList。记录空闲内存,删除第一个对象,记录内存,删除第二个对象,记录内存,计算差异,…,利润

您可能应该使用大量的数据来实现这一点。从1000开始,然后是10000、100000、1000000

编辑:由于amischiefr,已更正

编辑: 很抱歉编辑了你的文章,但如果你打算使用它,这是非常重要的(这是一个有点多的评论) . freeMemory并不像您想象的那样工作。首先,它的值由垃圾收集更改。其次,当java分配更多内存时,它的值会改变。仅仅使用freeMemory调用并不能提供有用的数据

试试这个:

public static void displayMemory() {
    Runtime r=Runtime.getRuntime();
    r.gc();
    r.gc(); // YES, you NEED 2!
    System.out.println("Memory Used="+(r.totalMemory()-r.freeMemory()));
}
或者您可以返回使用的内存并存储它,然后将其与以后的值进行比较。无论如何,记住2个gcs并从totalMemory()中减去


再次,很抱歉编辑您的帖子

HashMap保留对值和键的引用

ArrayList只需保留对该值的引用即可

因此,假设键使用与值相同的内存,HashMap使用的内存增加了50%(虽然严格来说,不是HashMap使用该内存,因为它只保留对它的引用)

另一方面,HashMap为基本操作(get和put)提供了恒定的时间性能,因此,尽管它可能会使用更多内存,但使用HashMap获取元素可能比使用ArrayList快得多

因此,接下来你应该做的是不要关心谁使用了更多的内存,而是他们有什么好处

为程序使用正确的数据结构比库的底层实现方式节省更多的CPU/内存

编辑

在格兰特·韦尔奇给出答案后,我决定测量2000000个整数

这是我的建议

这是输出

$
$javac MemoryUsage.java  
Note: MemoryUsage.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$java -Xms128m -Xmx128m MemoryUsage 
Using ArrayListMemoryUsage@8558d2 size: 0
Total memory: 133.234.688
Initial free: 132.718.608
  Final free: 77.965.488

Used: 54.753.120
Memory Used 41.364.824
ArrayListMemoryUsage@8558d2 size: 2000000
$
$java -Xms128m -Xmx128m MemoryUsage H
Using HashMapMemoryUsage@8558d2 size: 0
Total memory: 133.234.688
Initial free: 124.329.984
  Final free: 4.109.600

Used: 120.220.384
Memory Used 129.108.608
HashMapMemoryUsage@8558d2 size: 2000000

基本上,你应该使用“适合工作的正确工具”。因为有不同的实例需要密钥/值对(可以使用
HashM)
public class Payload {
    int key,b,c;
    Payload(int _key) { key = _key; }
}


import org.junit.Test;

import java.util.HashMap;
import java.util.Map;


public class Overhead {
    @Test
    public void useHashMap()
    {
        int i=0;
        try {
            Map<Integer, Payload> map = new HashMap<Integer, Payload>();
            for (i=0; i < 4000000; i++) {
                int key = (int)(Math.random() * Integer.MAX_VALUE);
                map.put(key, new Payload(key));
            }
        }
        catch (OutOfMemoryError e) {
            System.out.println("Got up to: " + i);
        }
    }

    @Test
    public void useArrayList()
    {
        int i=0;
        try {
            ArrayListMap map = new ArrayListMap();
            for (i=0; i < 9000000; i++) {
                int key = (int)(Math.random() * Integer.MAX_VALUE);
                map.put(key, new Payload(key));
            }
        }
        catch (OutOfMemoryError e) {
            System.out.println("Got up to: " + i);
        }
    }
}


import java.util.ArrayList;


public class ArrayListMap {
    private ArrayList<Payload> map = new ArrayList<Payload>();
    private int[] primes = new int[128];

    static boolean isPrime(int n)
    {
        for (int i=(int)Math.sqrt(n); i >= 2; i--) {
            if (n % i == 0)
                return false;
        }
        return true;
    }

    ArrayListMap()
    {
        for (int i=0; i < 11000000; i++)    // this is clumsy, I admit
            map.add(null);
        int n=31;
        for (int i=0; i < 128; i++) {
            while (! isPrime(n))
                n+=2;
            primes[i] = n;
            n += 2;
        }
        System.out.println("Capacity = " + map.size());
    }

    public void put(int key, Payload value)
    {
        int hash = key % map.size();
        int hash2 = primes[key % primes.length];
        if (hash < 0)
            hash += map.size();
        do {
            if (map.get(hash) == null) {
                map.set(hash, value);
                return;
            }
            hash += hash2;
            if (hash >= map.size())
                hash -= map.size();
        } while (true);
    }

    public Payload get(int key)
    {
        int hash = key % map.size();
        int hash2 = primes[key % primes.length];
        if (hash < 0)
            hash += map.size();
        do {
            Payload payload = map.get(hash);
            if (payload == null)
                return null;
            if (payload.key == key)
                return payload;
            hash += hash2;
            if (hash >= map.size())
                hash -= map.size();
        } while (true);
    }
}