我在三種環境中的 Windows 機器上用 C 撰寫代碼:
- 帶有 Ubuntu 的 Docker Linux 容器 - g 編譯器 (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
- Windows 上的 WSL Ubuntu 環境 - g 編譯器 (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
- Windows - gcc 編譯器(i686-posix-dwarf-rev0,由 MinGW-W64 專案構建)8.1.0
我正在處理大量資料集,基本上需要能夠將它們分解成盡可能大的塊以便在記憶體中進行操作。為了找到塊的大小,我想象如下:
size_t findOptimalSize(long long beginningSize) {
long long currentSize = beginningSize;
while (currentSize > 0) {
try {
std::vector<double> v(currentSize);
return currentSize;
} catch (std::bad_alloc &ex) {
currentSize /= 10;
}
}
return 0;
}
int main() {
long long size(50000000000000);
try {
std::vector<double> v(size);
std::cout << "success" << std::endl;
} catch (std::bad_alloc &ex){
std::cout << "badAlloc" << std::endl;
}
size_t optimal = findOptimalSize(size);
std::cout << "optimal size: " std::to_string(optimal);
return 0;
}
上面的代碼在 Windows 環境中完全符合預期。然而,在這兩個 Linux 環境中,雖然它總是能夠拋出第一個 bad_alloc 例外,但它隨后會執行以下兩種操作之一:
- 拋出帶有以下訊息的 SIGABRT:
new 不能滿足記憶體請求。這并不一定意味著您已經用完了虛擬記憶體。這可能是由于指標使用不當或共享庫過時引起的堆疊沖突
- 經過幾次迭代后,似乎陷入了無限回圈
std::vector<double> v(currentSize);(我最好的猜測是它接近 Linux 環境可用的記憶體量,并且它卡住等待額外的一點點額外記憶體釋放以滿足我的要求)
有什么方法可以完成我正在嘗試并在 Linux 環境中回避這些問題的方法嗎?我猜容器使事情變得復雜,并用它們復雜的記憶體管理邏輯混淆了我的簡單分配檢查。
在這些情況下如何檢查是否可以分配記憶體?
uj5u.com熱心網友回復:
容器沒有復雜的記憶體管理邏輯。您所看到的是一個令人驚訝的 Linux 策略的結果,稱為memory overcommit。
在 Linux 中,大分配不會失敗;malloc()總是成功。在您實際嘗試使用記憶體之前,不會實際分配記憶體。如果作業系統不能滿足需要,它會呼叫OOM 殺手,殺死行程直到它釋放足夠的記憶體。
為什么會存在這種情況?
Linux 計算機通常在其生命周期的不同階段運行許多異構行程。從統計上看,在任何時間點,它們都不需要為每個已分配(或稍后將在程式運行中分配)的虛擬頁面進行映射。
嚴格的非過度使用方案將在分配虛擬頁面時創建從虛擬地址頁面到物理 RAM 頁面幀的靜態映射。這將導致系統可以同時運行更少的程式,因為大量的 RAM 頁框將被保留為空。
(來源)
你可能會覺得這很荒謬。你不會孤單。這是一個極具爭議的系統。如果您最初的反應是“這很愚蠢”,我鼓勵您閱讀并暫停判斷。最終,無論您是否喜歡過度使用,這是所有 Linux 開發人員都必須接受和處理的生活事實。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/431392.html
標籤:C linux 码头工人 记不清 windows-subsystem-for-linux
下一篇:Go切片全決議
