8

次の静的割り当てはセグメンテーション違反を引き起こします

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はunlimitedに設定されています。

誰かが私に何が起こっているのかについてのヒントを教えてもらえますか?

4

4 に答える 4

5

ulimitがunlimitedに設定されていると言うとき、その-sオプションを使用していますか?それ以外の場合、これはスタック制限を変更せず、ファイルサイズ制限のみを変更します。

ただし、スタック制限があるようです。私は割り当てることができます:

double *u = malloc(200*2048*2048*(sizeof(double)));  // 6gb contiguous memory

そして、私が得るバイナリを実行します:

VmData:  6553660 kB

ただし、スタックに割り当てると、次のようになります。

double u[200][2048][2048];

VmStk:   2359308 kB

これは明らかに正しくありません(オーバーフローを示唆しています)。元の割り当てでは、2つで同じ結果が得られます。

Array:  VmStk:   3276820 kB
malloc: VmData:  3276860 kB

ただし、スタックバージョンを実行すると、アレイのサイズに関係なく、セグメンテーションフォールトを生成できません。設定されている場合は、実際にシステム上の合計メモリを超えている場合でも同様-s unlimitedです。

編集:

malloc失敗するまでループでテストを行いました。

VmData: 137435723384 kB  // my system doesn't quite have 131068gb RAM

ただし、スタックの使用量が4GBを超えることはありません。

于 2013-03-16T12:39:38.323 に答える
4

マシンに3.125GiBのデータを割り当てるのに十分な空きメモリがあると仮定すると、静的割り当てではこのメモリのすべてが連続している必要があり(実際には3次元配列です)、動的割り当てのみであるという事実に違いがあります。約2048*8 = 16 KiBの連続したブロックが必要です(これは、非常に小さい実際の配列へのポインターの配列へのポインターの配列です)。

オペレーティングシステムが、スタックメモリではなく、ヒープメモリにスワップファイルを使用する可能性もあります。

于 2013-03-16T11:49:06.273 に答える
2

Linuxのメモリ管理(特にスタック)については、ここで非常に良い議論があります。9.7スタックオーバーフロー、読む価値があります。

このコマンドを使用して、現在のスタックsoft limitが何であるかを調べることができます

ulimit -s

Mac OS Xでは、ハード制限は64MBです。cまたはRubyプログラムのMac OS Xで、ulimitを使用して、またはプロセスごとにスタックサイズを変更する方法を参照してください。

プログラムから実行時にスタック制限を変更できます。GNUコンパイラを使用したコンパイル中にLinuxでC++アプリケーションのスタックサイズを変更するを参照してください。

私はあなたのコードをそこのサンプルと組み合わせました、これが動作するプログラムです

#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;
}
于 2013-03-16T16:34:03.317 に答える
-3

スタックの限界に達しています。Windowsのデフォルトでは、スタックは1Mですが、十分なメモリがある場合はさらに大きくなる可能性があります。

多くの*nixシステムでは、デフォルトのスタックサイズは512Kです。

2048 * 2048 * 100 * 8バイトを割り当てようとしています。これは、2 ^ 25を超えています(スタックの場合は2Gを超えています)。使用可能な仮想メモリがたくさんあり、それでもこれをスタックに割り当てたい場合は、アプリケーションをリンクするときに別のスタック制限を使用してください。

Linux: gcc実行可能スタックサイズを増やす方法は? GNUコンパイラでのコンパイル中にLinuxのC++アプリケーションのスタックサイズを変更する

Windows: http: //msdn.microsoft.com/en-us/library/tdkhxaks%28v=vs.110%29.aspx

于 2013-03-16T11:53:41.303 に答える