以下静态分配给出了分段错误
double U[100][2048][2048];
但是下面的动态分配很顺利
double ***U = (double ***)malloc(100 * sizeof(double **));
for(i=0;i<100;i++)
{
U[i] = (double **)malloc(2048 * sizeof(double *));
for(j=0;j<2048;j++)
{
U[i][j] = (double *)malloc(2048*sizeof(double));
}
}
linux中的ulimit设置为无限制。
有人能给我一些关于发生什么的暗示吗?
答案 0 :(得分:5)
当您说ulimit设置为无限制时,您使用的是-s
选项吗?否则,这不会改变堆栈限制,只会改变文件大小限制。
但是,无论如何都会出现堆栈限制。我可以分配:
double *u = malloc(200*2048*2048*(sizeof(double))); // 6gb contiguous memory
运行我得到的二进制文件:
VmData: 6553660 kB
但是,如果我在堆栈上分配,那就是:
double u[200][2048][2048];
VmStk: 2359308 kB
这显然不正确(暗示溢出)。使用原始分配,两者给出相同的结果:
Array: VmStk: 3276820 kB
malloc: VmData: 3276860 kB
但是,运行堆栈版本,无论数组的大小如何,我都无法生成段错误 - 即使它超过系统上实际的总内存,如果设置了-s unlimited
。
编辑:
我在循环中使用malloc
进行了测试,直到失败为止:
VmData: 137435723384 kB // my system doesn't quite have 131068gb RAM
然而,堆栈使用量永远不会超过4gb。
答案 1 :(得分:3)
假设你的机器实际上有足够的可用内存来分配3.125 GiB的数据,差异很可能在于静态分配需要所有这些内存是连续的(它实际上是一个三维数组),而动态分配只需要大约2048 * 8 = 16 KiB的连续块(它是指向非常小的实际数组的指针数组的指针数组)。
当操作系统用完时,操作系统也可能使用交换文件作为堆内存,而堆栈内存则不然。
答案 2 :(得分:2)
对Linux内存管理 - 特别是堆栈 - 有一个非常好的讨论:9.7 Stack overflow,值得一读。
您可以使用此命令查找当前堆栈soft limit
ulimit -s
在Mac OS X上,硬限制为64MB,请参阅How to change the stack size using ulimit or per process on Mac OS X for a C or Ruby program?
您可以在程序中修改运行时的堆栈限制,请参阅Change stack size for a C++ application in Linux during compilation with GNU compiler
我将您的代码与示例相结合,这是一个有效的程序
#include <stdio.h>
#include <sys/resource.h>
unsigned myrand() {
static unsigned x = 1;
return (x = x * 1664525 + 1013904223);
}
void increase_stack( rlim_t stack_size )
{
rlim_t MIN_STACK = 1024 * 1024;
stack_size += MIN_STACK;
struct rlimit rl;
int result;
result = getrlimit(RLIMIT_STACK, &rl);
if (result == 0)
{
if (rl.rlim_cur < stack_size)
{
rl.rlim_cur = stack_size;
result = setrlimit(RLIMIT_STACK, &rl);
if (result != 0)
{
fprintf(stderr, "setrlimit returned result = %d\n", result);
}
}
}
}
void my_func() {
double U[100][2048][2048];
int i,j,k;
for(i=0;i<100;++i)
for(j=0;j<2048;++j)
for(k=0;k<2048;++k)
U[i][j][k] = myrand();
double sum = 0;
int n;
for(n=0;n<1000;++n)
sum += U[myrand()%100][myrand()%2048][myrand()%2048];
printf("sum=%g\n",sum);
}
int main() {
increase_stack( sizeof(double) * 100 * 2048 * 2048 );
my_func();
return 0;
}
答案 3 :(得分:-3)
你正在达到堆栈的限制。默认情况下,在Windows上,堆栈为1M,但如果有足够的内存,则可以增长更多。
在许多* nix系统上,默认堆栈大小为512K。
您正在尝试分配2048 * 2048 * 100 * 8字节,超过2 ^ 25(堆叠超过2G)。如果您有大量可用的虚拟内存且仍希望在堆栈上分配此内存,请在链接应用程序时使用不同的堆栈限制。
Linux中: How to increase the gcc executable stack size? Change stack size for a C++ application in Linux during compilation with GNU compiler
视窗: http://msdn.microsoft.com/en-us/library/tdkhxaks%28v=vs.110%29.aspx