作为一名前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
首先,Erlang 变量始终只是一个单词(32 或 64 位,具体取决于您的计算机)。 单词的 2 位或更多位用作类型标记。其余部分可以保存"即时"值,例如"固定"整数、原子、空列表 ([]) 或 Pid;或者它可以保存指向堆上存储的数据(元组、列表、"bignum"整数、浮点数等)的指针。元组有一个标题字,指定其类型和长度,后跟每个元素一个词。上的列表单元格仅使用 2 个单词(其指针已对类型进行编码):头和尾元素。
例如:如果 A={foo,1,[]},则 A 是一个指向堆上的单词的单词,表示"I'm a 3 元组",后跟分别包含原子 foo、fixnum 1 和空列表的 3 个单词。如果 A=[1,2],则 A 是一个表示"我是列表单元格指针"的单词,指向第一个单元格的头单词(包含固定数 1);单元格的下一个尾词是另一个列表单元格指针,指向包含 2 的头词,后跟包含空列表的尾词。浮点数由标头字和 8 个字节的双精度浮点数据表示。bignum 或二进制是一个标题字加上保存数据所需的任意数量的单词。等等。例如,请参阅 http://stenmans.org/happi_blog/?p=176 以获取更多信息。
要估计大小,您需要知道数据在元组和列表方面的结构,并且需要知道整数的大小(如果太大,它们将使用 bignum 而不是固定编号;限制为 28 位(包括 32 位机器上的符号)和 64 位机器上的 60 位)。
编辑:https://github.com/happi/theBeamBook 是BEAM Erlang虚拟机内部较新的良好资源。
这是你想要的吗?
1> erts_debug:size([1,2]).
4
有了它,您至少可以弄清楚一个术语有多大。返回的大小以文字为单位。
Erlang 将整数作为"数组",因此您无法真正以与 c 相同的方式估计它,您只能预测整数将有多长并计算存储它们所需的平均字节数
检查:http://www.erlang.org/doc/efficiency_guide/advanced.html,您可以使用erlang:memory()
功能来确定实际金额