【问题标题】:Estimating memory scope of erlang datastructure估计erlang数据结构的内存范围
【发布时间】:2017-10-03 15:40:22
【问题描述】:

作为一名前 C 程序员和现任 Erlang 黑客,有人提出了一个问题。

如何估计我的 erlang 数据结构的内存范围?

假设我在 C 中有一个 1k 整数的数组,估计它的内存需求很容易,只是我的数组的大小乘以整数的大小,1k 32 位整数将占用 4kb 或内存,还有一些恒定数量的指针和索引。

然而,在 erlang 中估计内存使用量有点复杂,erlangs 数组结构中的条目占用多少内存?我如何估计动态大小的整数的大小。

我注意到在 erlang 中扫描数组中的整数相当慢,在 erlang 中扫描大约 1M 整数的数组几乎需要一秒钟,而一段简单的 c 代码将在 2 毫秒左右完成,这很可能是由于数据结构占用的内存量。

我问这个,不是因为我是一个速度狂,而是因为估计内存,至少在我的经验中,是确定软件可扩展性的好方法。


我的测试代码:

首先是C代码:

#include <cstdio>
#include <cstdlib>
#include <time.h>

#include <queue>  
#include <iostream>

class DynamicArray{
protected:
  int* array;
  unsigned int size;
  unsigned int max_size;

public:
  DynamicArray() {
    array = new int[1];
    size = 0;
    max_size = 1;
  }

  ~DynamicArray() {
    delete[] array;
  }

  void insert(int value) {
    if (size == max_size) {
      int* old_array = array;
      array = new int[size * 2];
      memcpy ( array, old_array, sizeof(int)*size );

      for(int i = 0; i != size; i++)
        array[i] = old_array[i];
      max_size *= 2;
      delete[] old_array;
    }
    array[size] = value;
    size ++;
  }

  inline int read(unsigned idx) const {
    return array[idx];
  }

  void print_array() {
    for(int i = 0; i != size; i++)
      printf("%d ", array[i]);
    printf("\n ");

  }

  int size_of() const {
    return max_size * sizeof(int);
  }    

};


void test_array(int test) {
  printf(" %d ", test);
  clock_t t1,t2;
  t1=clock();
  DynamicArray arr;
  for(int i = 0; i != test; i++) {
    //arr.print_array();
    arr.insert(i);
  }
  int val = 0;
  for(int i = 0; i != test; i++)
    val += arr.read(i);
  printf(" size %g MB ", (arr.size_of()/(1024*1024.0)));  
  t2=clock();
  float diff ((float)t2-(float)t1);
  std::cout<<diff/1000<< " ms" ;
  printf(" %d \n", val == ((1 + test)*test)/2);
}

int main(int argc, char** argv) {
  int size = atoi(argv[1]);
  printf(" -- STARTING --\n");
  test_array(size);
  return 0;
}

和erlang代码:

-module(test).

-export([go/1]).

construct_list(Arr, Idx, Idx) ->
    Arr;
construct_list(Arr, Idx, Max) ->
    construct_list(array:set(Idx, Idx, Arr), Idx + 1, Max).

sum_list(_Arr, Idx, Idx, Sum) ->
    Sum;
sum_list(Arr, Idx, Max, Sum) ->
    sum_list(Arr, Idx + 1, Max, array:get(Idx, Arr) + Sum ).

go(Size) ->
    A0 = array:new(Size),
    A1 = construct_list(A0, 0, Size),
    sum_list(A1, 0, Size, 0).

为c代码计时:

bash-3.2$ g++ -O3 test.cc -o test
bash-3.2$ ./test 1000000
 -- STARTING --
 1000000  size 4 MB 5.511 ms 0 

和erlang代码:

1> f(Time), {Time, _} =timer:tc(test, go, [1000000]), Time/1000.0.
2189.418

【问题讨论】:

  • 小提示:1k 32bit 整数将占用 1024*4 = 4kb 内存
  • @IlyaBursov 你是对的 :)
  • 另外,请注意访问array 元素的时间不是一个常数。所以最好遍历list的整数,需要O(n)步。
  • @danechkin 数据结构是称为数组的事件这一事实有点误导:)

标签: c arrays memory erlang


【解决方案1】:

首先,Erlang 变量始终只是一个单词(32 位或 64 位,具体取决于您的机器)。字的 2 位或更多位用作类型标记。余数可以保存“立即”值,例如“fixnum”整数、原子、空列表 ([]) 或 Pid;或者它可以保存指向存储在堆上的数据的指针(元组、列表、“bignum”整数、浮点数等)。元组有一个标头词,指定其类型和长度,然后每个元素一个词。上的列表单元仅使用 2 个单词(它的指针已经对类型进行了编码):头元素和尾元素。

例如:如果 A={foo,1,[]},那么 A 是一个词,指向堆上的一个词,说“我是一个 3 元组”,后跟 3 个包含原子 foo 的词,即分别为fixnum 1和空列表。如果 A=[1,2],那么 A 是一个单词,表示“我是一个列表单元格指针”,指向第一个单元格的头部单词(包含固定数字 1);单元格的后面的尾字是另一个列表单元格指针,指向一个包含 2 的头字,后面是一个包含空列表的尾字。浮点数由一个标题字和 8 个字节的双精度浮点数据表示。 bignum 或二进制是标题字加上保存数据所需的字数。等等。参见例如http://stenmans.org/happi_blog/?p=176 了解更多信息。

要估计大小,您需要知道数据是如何按照元组和列表来构造的,并且您需要知道整数的大小(如果太大,它们将使用 bignum 而不是 fixnum;限制在 32 位机器上是 28 位,包括符号,在 64 位机器上是 60 位。

编辑:https://github.com/happi/theBeamBook 是 BEAM Erlang 虚拟机内部的一个较新的好资源。

【讨论】:

    【解决方案2】:

    这是你想要的吗?

    1> erts_debug:size([1,2]).
    4
    

    有了它,您至少可以弄清楚一个术语有多大。返回的大小以字为单位。

    【讨论】:

      【解决方案3】:

      Erlang 将整数作为“数组”,因此您无法像 c 那样真正估算它,您只能预测整数的长度并计算存储它们所需的平均字节数

      检查:http://www.erlang.org/doc/efficiency_guide/advanced.html,您可以使用erlang:memory()函数确定实际金额

      【讨论】:

      • erlang:memory 只会回答正在运行的应用程序的问题,我想说的是存储 10mio 条目将占用 40mb 内存。不只是让我们从 100 开始,看看内存是否喜欢它 :)
      • @MartinKristiansen 所以,请阅读我的第一段,如果您知道这 10m 个数字的范围 - 您可以估计每个数字需要多少字节
      • 这是我不明白的,小整数会占用 60(64) 位,使它们成为 16 字节整数,但是扫描它们比 c 程序慢五百倍..
      • 即使是小整数,erlang也必须存储:变量类型,数组长度,数字中每个数字至少字节,这可以解释:内存使用和性能问题
      • @MartinKristiansen 是的,这就是我的意思,你也可以假设每个整数都是结构体,整数数组是某种动态分配的链表
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-19
      • 1970-01-01
      • 2013-09-27
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      相关资源
      最近更新 更多