Java:数据结构内存估计

时间:2012-03-22 01:40:35

标签: java optimization memory data-structures

有没有人有各种数据结构的粗略经验法估算器列表? e.g。

  
      
  • 阵列
  •   
  • 解释
  •   
  • 包含HashMap
  •   
  • LinkedLists
  •   

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

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

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

当然它会因此而变化很大,但是,即使是粗略的2因素估计也会非常有用。

5 个答案:

答案 0 :(得分:3)

答案 1 :(得分:2)

此表非常详尽,并且精确处理以每个条目/元素的字节数为单位测量的JDK实现选项。如果您想在自己的计算机上执行此操作 - 如果您在另一台计算机上运行,​​可能 - 此Google代码网站将允许您下载其来源。 http://code.google.com/p/memory-measurer/wiki/ElementCostInDataStructures

答案 2 :(得分:0)

这非常粗糙,但这些估计应该是正确的。这些是针对简单的数据结构,不包括长度变量或任何其他倾向于包含在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)

答案 3 :(得分:0)

这是一个简单的程序,只占用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倍。

答案 4 :(得分:0)

来自twitter工作人员的Infoq, there is a presentation infoq-11-nov-jvmperformance.mp3:Pdf-slides,音频:mp3和视频。

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