有没有使用可变长度阵列的任何开销?
-
19-09-2019 - |
题
是否有使用可变长度数组一些开销?可能数组的大小通过在运行时命令行参数传递?为什么引入,相对于自动和动态分配一个数组?
解决方案
VLA确实有一些开销(与“普通”的命名编译时大小的数组)。
首先,它运行时长度,但该语言提供了装置在运行时,以获得阵列的实际大小(使用sizeof
)。这直接意味着数组的实际大小,必须保存在某个地方。这导致一些无关紧要的每个阵列内存开销。然而,由于沃拉斯只能被声明为自动对象,该内存开销是不是任何人会注意到。它就像声明积分型的额外的本地变量。
其次,VLA通常分配在堆,但由于其大小可变的,在一般情况下,在存储器中它的确切位置是在编译时已知的。由于这个原因,底层实现通常具有实现它作为一个指针到一个存储块。这引入了一些额外的内存开销(用于指针),而这又是由于上述原因完全不显着。这也引入了轻微的性能开销,因为我们为了找到实际的阵列读取指针值。这是一种访问malloc
-ED阵列,当你(和不与命名的编译时大小的数组获取)相同的开销。
由于VLA的大小是一个运行时间的整数值,它可以,当然,被作为一个命令行参数来传递。 VLA不关心其中其尺寸是来自
VLA引入作为运行时大小的数组具有低分配/解除分配成本。它们适合“普通”命名的编译时大小的阵列(其具有几乎为零的分配解除分配成本,但固定大小)和malloc
-ED阵列(已运行时间的大小,但相对高的分配解除分配成本)之间。
VLA服从[几乎]相同范围相关的寿命的规则自动(即本地)对象,这意味着,在一般情况下,它们不能代替malloc
-ED阵列。当你需要与典型自动寿命的快速运行时大小的数组它们的适用性限制在的情况。
其他提示
有一些运行时的开销变长数组,但是你将不得不工作相当辛苦来衡量它。注意如果sizeof(vla)
是一个可变长度数组vla
是不是编译时间常数。
的阵列的大小可被传递给函数在运行时。如果您选择从一个命令行参数采取的尺寸和转换是成整数,并传递到在运行时的功能,所以它 - 它会工作
使用变长数组,因为变量被自动分配到正确的大小和从函数退出自动释放。这样可以防止过度分配空间(分配的最大可能的大小时,你主要是用最小尺寸的工作足够的空间),并避免与记忆问题清理。
此外,与多维数组, AFAIK 它表现得更像的Fortran - 可以动态配置所有的尺寸,而不是被卡住固定的尺寸,但所有阵列的前缘的尺寸。
的用于VLA一些运行时间开销混凝土证据 - 至少与SPARC(Solaris 10上)GCC 4.4.2
考虑下面的两个文件:
vla.c - 使用可变长度数组
#include <assert.h>
#include <stddef.h>
extern size_t identity_matrix(int n, int m);
size_t identity_matrix(int n, int m)
{
int vla[n][m];
int i, j;
assert(n > 0 && n <= 32);
assert(m > 0 && m <= 32);
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
vla[i][j] = 0;
}
vla[i][i] = 1;
}
return(sizeof(vla));
}
fla.c - 使用固定长度的阵列
#include <assert.h>
#include <stddef.h>
extern size_t identity_matrix(int n, int m);
size_t identity_matrix(int n, int m)
{
int fla[32][32];
int i, j;
assert(n > 0 && n <= 32);
assert(m > 0 && m <= 32);
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
fla[i][j] = 0;
}
fla[i][i] = 1;
}
return(sizeof(fla));
}
汇编和对象文件大小
为了比较的目的,本地阵列的名称是不同的(vla
VS fla
),和在阵列上的尺寸是当它被声明不同 - 否则,文件是相同的
我使用编译:
$ gcc -O2 -c -std=c99 fla.c vla.c
在对象文件大小有些不同 - 如通过“LS”和由“尺寸”测量两者:
$ ls -l fla.o vla.o
-rw-r--r-- 1 jleffler rd 1036 Jan 9 12:13 fla.o
-rw-r--r-- 1 jleffler rd 1176 Jan 9 12:13 vla.o
$ size fla.o vla.o
fla.o: 530 + 0 + 0 = 530
vla.o: 670 + 0 + 0 = 670
我没有做广泛的测试,看看有多少开销是固定的,又有多少是可变的,但开销使用VLA。
我只是不知道是否有使用可变长度数组一些开销?
都能跟得上
能阵列的尺寸可以通过命令行参数在运行时通过?
是
为什么引入,相对于自动和动态分配一个数组?
自动分配只允许在编译时已知的固定大小。
动态分配(malloc
)将存储在堆,它有一个大的存储器空间,但是较慢的访问。阵列
VLA工作通过将阵列中的堆。这使得分配和存取速度极快,的但强>堆通常是小的(几KB的),并且当所述VLA堆栈溢出,这是从一个无限递归不可区分的。
应该有VLAS很少的开销(在最应该导致除了堆栈指针)。动态分配需要人工存储器管理和大于VLA的基于堆栈的分配速度较慢,并且阵列的“自动”声明需要阵列尺寸编译时表达式。但是,请注意,如果发生堆栈溢出,就会造成未定义的行为,所以保持VLAS相对较小。
您可以通过通过命令行参数数组的大小,但你必须编写代码来处理自己。