【问题标题】:Java: Data Structure Memory EstimatesJava:数据结构内存估计
【发布时间】:2016-01-14 04:01:53
【问题描述】:

是否有人列出了各种数据结构的粗略估计规则?例如

  • 数组
  • 列表
  • 哈希映射
  • 链接列表

我记得在不同的地方看到过一些这样的估计,但我现在似乎找不到。

我知道它实际上非常复杂,尤其是对于像 HashMaps 这样的东西,但我正在寻找一些非常粗糙的东西,比如:

Memory(HashMap) = fixedOverhead + variableOverhead * tableSize + A*numKeys + B*numValues + Memory(allKeys) + Memory(allValues)

当然,它会根据这个和那个而有很大的不同,但即使是粗略的 2 倍以内的估计也会非常有用。

【问题讨论】:

  • 我知道我已经多次回答了这个问题,但我什至找不到自己的帖子。这是热点的非常简短、不完整的版本:每个对象都有 2 个单词开销并且是 8 字节对齐的。数组有一个额外的 4 字节的大小。参考大小取决于 JVM 位数,但 64 位系统上
  • 我想知道 visualvm 是否可以为您执行此操作...有一个内存分析器,但我从未使用过它。
  • 我也没有找到你的答案 =D 如果你能找到一个涵盖这个问题的旧答案,那就太棒了。
  • 编写一个 shell 脚本,它将初始化其中一个,取决于 Array、List 的参数 1 和元素数量(1M、2M、4M)的第二个参数,然后在 3 个循环中调用这个程序,迭代你的程序,并在这样做的同时减少 -Xmx -Param,以找出下限。我希望这些集合的大小几乎相等,与集合的类型无关。

标签: java optimization memory data-structures


【解决方案1】:

【讨论】:

  • 不错的发现!这正是我一直在寻找的
  • 这个也有帮助slideshare.net/aszegedi/…
  • 那是我以为我看到的,但当我真正回去看时,我并没有找到它。谢谢!
  • 由于链接中没有提到他们正在谈论的 JVM(这是一个严重的缺陷,应该相当令人不安),它可能是正确的。但是,如果我们谈论的是 Hotspot,那么给定的对象标头已经过时了大约十年。哎呀,他甚至没有提到内存是 8 字节对齐的。这篇文章充其量是可疑的......好吧,或者因为他是 IBM 人,所以他在谈论他们的 JVM——我不知道那个。
【解决方案2】:

此表非常详尽,准确地处理了 JDK 实现选择,以每个条目/元素的字节数衡量。如果你想在你自己的机器上做——如果你在另一台机器上运行,也许——这个谷歌代码网站会让你下载它的源代码。 http://code.google.com/p/memory-measurer/wiki/ElementCostInDataStructures

【讨论】:

    【解决方案3】:

    这很粗略,但这些估计应该是正确的。这些是针对基本数据结构的,不包括长度变量或任何其他倾向于包含在 Java 中的额外内容。

    dataType 是存储的数据类型

    Array: (length n)
        n*sizeOf(dataType)
    
    LinkedList:
        n*(sizeOf(dataType)+sizeOf(pointer))+sizeOf(pointer[head pointer])
    
    List: 
        Array-backed=SpaceEfficiency(Array)
        LinkedList-backed=SpaceEfficiency(LinkedList)
    
    HashMap: with v values, k keys
        v*sizeOf(valueDataType)
    
    Tree: k-way tree with n nodes
        n*(sizeOf(nodeDataType)+(k*sizeOf(pointer)))+sizeOf(pointer[head pointer])
    
    Graph: e edges, v vertices
        AdjacencyList:
            at most: v*((v*sizeOf(vertexDataType))+(e*sizeOf(pointer))) fully connected graph
            at least: v*sizeOf(vertexDataType) disconnected graph
        AdjacencyMatrix:
            v^2*sizeOf(int)
    

    【讨论】:

    • 这很有用,但我也知道如何从理论上分析这些东西 =)。这是我感兴趣的常量:数组中每个项目的开销是多少(以字节为单位)?在链表中?在 HashMap 中?什么是固定开销?我想要比这更详细的东西,它实际上是没有任何常量的渐近符号。
    • 我很困惑,除了我们理论上确定的东西之外,还有什么问题。所以我的意思是数组中应该有 no 每个项目的开销,对吗?链表中的每项开销只是指向下一个节点的指针的开销,HashMap 中的开销是不存在的(除了内存中用于存储执行哈希算法的代码的空间),因为它只是数组。您是否正在寻找比这更具体的东西?任何更具体的东西都是java实现选择的结果。或者这就是你要找的东西?我觉得这很有趣:p
    • OP 正在询问 Java 实现选择,@Mako。
    【解决方案4】:

    这是一个简单的程序,它只消耗 RAM:

    import java.util.*;
    /**
        RamInit (c) GPLv3
    
        @author Stefan Wagner
        @date Do 22. Mär 08:40:40 CET 2012
    
    */
    public class RamInit
    {
        private java.lang.Object consumer; 
    
        public RamInit (char type, int size)
        {
            switch (type) 
            {
                case 'a': Integer [] ai = new Integer [size]; 
                    for (int i = 0; i < size; ++i) 
                        ai[i] = i; 
                    consumer = ai; 
                    break;
                case 'l': List<Integer> li = new ArrayList<Integer> (); 
                    for (int i = 0; i < size; ++i) 
                        li.add (i); 
                    consumer = li;
                    break;
                case 'h': HashMap <Integer, Integer> hm = new HashMap <Integer, Integer> (); 
                    for (int i = 0; i < size; ++i) 
                        hm.put (i, size - i); 
                    consumer = hm;
                    break;
                case 'L': LinkedList <Integer> ll = new LinkedList <Integer> (); 
                    for (int i = 0; i < size; ++i) 
                        ll.add (i);     
                    consumer = ll;          
                    break;
                default: System.err.println ("invalid: " + type);
            }
        }
    
        public static void main (String args[])
        {
            char type = 'a';
            int size = 1000000; // 1M
            if (args.length == 2)
            {
                type = args[0].charAt (0);
                size = Integer.parseInt (args[1]);
            }
            try {
                new RamInit (type, size);
            }
            catch (OutOfMemoryError oome)
            {
                System.exit (1);
            }
        }
    }
    

    这是一个非常简单的脚本来测试它:

    #!/bin/bash
    
    iterProg () {
    ram=$1
    maxram=$2 
    typ=$3
    size=$4
    # echo java -Xmx${ram}M RamInit $typ $((size*1000*1000)) 
    echo -n "." 
    java -Xmx${ram}M RamInit $typ $((size*1000*1000)) && echo -en "\n"$typ $size ${ram}M || { 
        if (($ram==$maxram))
        then
            # echo "fail" 
            return 
        else 
            iterProg $((ram+1)) $maxram $typ $size 
        fi
        }
    }
    
    # try from 16 MB to 256
    for typ in {a,l,h,L}; do 
      for size in {1,2,4}; do 
        iterProg $((size*17+1)) 256 $typ $size 
      done
    done
    

    它是一个原始迭代器,应该用更复杂的东西代替 - 例如,如果你需要 37MB 来调用带有 Collection a 和 1M 元素的 RamInit,你应该从 2M 元素开始。

    并且你应该在二分搜索中选择步骤,例如如果 20M 太少,检查 128,然后是 (20+128)/2,然后是平均值,这取决于成功或失败,下限或上限。

    由于 HashMap 每个元素存储 2 个 Int,它可以从 List/Array/Vector 的大约两倍大小开始。然而——时光荏苒,边写边写:

    bash iterRamFind.sh 
    ..
    a 1 19M.....
    a 2 39M...............
    a 4 83M..
    l 1 19M.......
    l 2 41M.......................
    l 4 91M..............................................
    h 1 63M.............................................................................................
    h 2 127M...........................................................................................................................................................................................
    h 4 255M......................
    L 1 39M.................................................
    L 2 83M...............................................................................................
    L 4 163
    

    值 17 可以从第一次实验中得到解释。 正如我们所看到的,尺寸几乎以线性方式增加。

    修改代码以检查您使用 Longs 的影响,这取决于您 - 我猜您将以 2 倍结束。

    【讨论】:

      【解决方案5】:

      Infoq, there is a presentationinfoq-11-nov-jvmperformance.mp3 来自 Twitter 上的一名工作人员:Pdf-slides、Audio:mp3 和 Video。

      它处理了很多关于集合和 JVM 中对象大小的其他细节。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-19
        • 1970-01-01
        • 2010-12-05
        • 1970-01-01
        • 2011-12-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多