簡體   English   中英

當需要超過 16GB 的連續 memory 時,Memory 分配失敗

[英]Memory allocation failed when required more than 16GB contiguous memory

我的工作站有 128GB memory。 我無法分配占用(連續)memory 超過 ~16GB 的數組。 但我可以分配多個 arrays,每個大約需要 15GB。

示例代碼:

#include <stdlib.h>
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
int MM = 1000000;
int NN = 2200; // 2000 is okay, used ~16GB memory; 2200 produces Segmentation fault

double* testMem1d;
testMem1d  = (double*) malloc(MM*NN*sizeof(double));

double* testMem1d1; // NN=2000, allocate another array (or two) at the same time is okay
testMem1d1 = (double*) malloc(MM*NN*sizeof(double));

cout << "testMem1d allocated" << endl;
cin.get(); // here is okay, only malloc but not accessing the array element

cout << "testMem1d[MM*NN-1]=" << testMem1d[MM*NN-1]<< endl;
cout << "testMem1d1[MM*NN-1]=" << testMem1d1[MM*NN-1]<< endl;

// keep running and check the physical memory footprint
for (int tt=0;tt<1000;tt++)
{
    for (int ii=0; ii<MM*NN; ii++)
    {
        testMem1d[ii]=ii;
        testMem1d1[ii]=ii;
    }
    cout << "MM=" << MM << ", NN=" << NN << ", testMem1d[MM*NN-1]=" << testMem1d[MM*NN-1]<< endl;
}
}

如果不是基本問題,請忽略我在 c++ 中使用 malloc()。 (是嗎?)出於其他原因,我需要/想要使用 malloc() 。

一些觀察:(1)分配多個 arrays,每個小於 15GB,很好(2)只做 malloc() 很好。 訪問數組元素時出現“分段錯誤”。

我認為可能有一些系統設置限制了 memory 分配。 從“ulimit -a”看來一切都很好。 由於該程序可以訪問 64 位虛擬地址空間,我找不到任何只限制連續 memory 分配的原因。

操作系統:Ubuntu 16.04。 我用 mcmodel=large 嘗試了 g++ 和 icc。 這似乎無關緊要。

uname -a
Linux 4.4.0-143-generic #169-Ubuntu SMP Thu Feb 7 07:56:38 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

ulimit -a 
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 515031
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) unlimited
cpu time               (seconds, -t) unlimited
max user processes              (-u) 515031
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

編輯:

(1) mallc() 實際上返回 NULL [to mcleod_ideafix]

(2) [對茲沃爾]

free -m
              total        used        free      shared  buff/cache   available
Mem:         128809       18950      107840        1129        2018      107910
Swap:           974         939          35

乘法MM*NN*sizeof(double)是左結合的,所以它發生為(MM * NN) * sizeof(double) 在具有等式MM * NN的 32 位int平台上,它不能用 32 位int表示並且溢出(並且發生未定義的行為)並環繞-2094967296 2200000000 然后這個值被提升為sizeof(double)的通用類型,到size_t 這是有符號類型到無符號類型的轉換,其中有符號值不能以無符號類型表示,因此轉換是實現定義的。 在帶有 64 位size_t符號擴展的二進制補碼中,它應該導致18446744071614584320 然后這個值乘以我假設等於8sizeof(double) ,它會溢出多次(這是安全的, size_t unsigned)並導致18446744056949813248字節。 你的機器沒有那么多 memory,所以malloc返回 NULL。

這就是為什么最好將sizeof作為malloc調用中的第一個操作數:

malloc(sizeof(double) * MM * NN);

在這種情況下,操作數將在乘法之前提升為size_t

但這還不夠,因為在testMem1d[MM*NN-1]ii<MM*NN中仍然會發生溢出。 因此,您應該將MMNN的類型更改為具有足夠位來保存結果的類型。

size_t MM = 1000000;
size_t NN = 2200;

或者在每次可能溢出的乘法之前將值轉換為正確的類型。

注意語句cout << "testMem1d[MM*NN-1]=" << testMem1d[MM*NN-1]<< endl; cout << "testMem1d1[MM*NN-1]=" << testMem1d1[MM*NN-1]<< endl; cout << "testMem1d[MM*NN-1]=" << testMem1d[MM*NN-1]<< endl; cout << "testMem1d1[MM*NN-1]=" << testMem1d1[MM*NN-1]<< endl; 正在讀取未初始化的 memory。

更喜歡在 C++ 中使用new的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM