2012-02-03 26 views
6

Tôi cố gắng sử dụng mmap() để thao tác bộ nhớ ảo. Tôi muốn dự trữ và cam kết một khu vực của bộ nhớ. Tôi đã thử nghiệm mã này:Tại sao gọi mmap() với kích thước lớn không thành công?

const unsigned long gygabyte = 1024 * 1024 * 1024; 
const unsigned long gygabyteCount = 2; 
const unsigned long maxCapacity = gygabyteCount * gygabyte; 

int main() 
{ 
    char* pMemory; 

    pMemory = (char*)mmap(NULL, maxCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 
    if (mprotect(pMemory, maxCapacity, PROT_READ | PROT_WRITE) != 0) 
    { 
     cout << "Memory Allocation has failed" << endl; 
    } 
    usleep(-1); 

    return 0; 
} 

Tôi đã chạy một vài bản sao chương trình của mình (ví dụ 6) từ thiết bị đầu cuối. Tôi chưa bao giờ thấy "Phân bổ bộ nhớ đã thất bại" trong bất kỳ cái nào. Tôi đang chạy trên Ubuntu 64-bit với RAM 4GB. Bất cứ ai có thể cho tôi biết một cái gì đó về điều này?

+1

đọc về ghi đè bộ nhớ – PlasmaHH

+0

Mã bạn đăng không cam kết bất kỳ thứ gì. Hãy thử đi qua các vùng bộ nhớ đó. – Mat

Trả lời

11

mmap giữ một khu vực của không gian địa chỉ ảo của quá trình, nhưng không ngay lập tức phân bổ RAM vật lý cho nó. Do đó, trên nền tảng 64 bit, bạn có thể đặt trước số tiền khổng lồ mà không bị lỗi (mặc dù bạn vẫn cần kiểm tra lỗi; mã ví dụ của bạn không). Các trang vật lý của RAM được cấp phát sau khi bộ nhớ được truy cập.

mprotect chỉ thay đổi quyền truy cập đọc/ghi của bộ nhớ đã đặt trước; nó sẽ không làm cho nó cư trú trong RAM hoặc. Bạn sẽ nhận được hiệu ứng tương tự bằng cách chuyển số PROT_READ | PROT_WRITE thay vì PROT_NONE đến mmap và xóa cuộc gọi đến mprotect.

Nếu bạn cần bộ nhớ cư trú trong RAM ngay lập tức, hãy sử dụng mlock cho điều đó. Nó sẽ thất bại nếu không có đủ RAM. Trên nhiều nền tảng Linux (bao gồm cả Ubuntu), có giới hạn tài nguyên (RLIMIT_MEMLOCK) hạn chế dung lượng bộ nhớ mà bất kỳ quá trình nào có thể khóa; bạn có thể điều chỉnh điều này với ulimit -l.

+0

Phải như thế này? 'pMemory = (char *) mmap (NULL, maxCapacity, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); mlock (pMemory, maxCapacity) 'Tôi nghĩ rằng bộ nhớ được sử dụng trong mlock() không phải là bộ nhớ được đặt trước bởi mmap(). – antpetr89

+0

Tôi đã cố gắng đặt trước 1GB và cam kết bằng cách này. Nhưng mlock() trả về -1. – antpetr89

+1

@ user1173593: Kiểm tra giá trị của 'errno' sau đó. Nó cũng có thể là 'EPERM', chỉ ra rằng giới hạn tài nguyên của bạn quá thấp (bạn có thể đặt nó bằng' ulimit -l', nhưng có lẽ cũng có giới hạn cứng), hoặc có lẽ là 'ENOMEM', chỉ ra rằng không đủ bộ nhớ hoặc các lỗi khác được ghi trong manpage. –

0

Trước tiên, bạn nên kiểm tra kết quả của mmap. Trong trường hợp nó trả về MAP_FAILED, điều đó có nghĩa là việc phân bổ không thành công. Hạt nhân sẽ không thực sự phân bổ quá nhiều bộ nhớ cùng một lúc, nhưng thay vì sẽ ánh xạ không gian vật lý hoặc trao đổi theo yêu cầu khi bạn truy cập vào các vùng tương ứng của khối đó.

Trong trường hợp cụ thể của bạn, bạn không cần một cuộc gọi riêng biệt để mprotect, kể từ khi đi qua những lá cờ cho toàn bộ khu vực có thể được thực hiện tại thời điểm gọi mmap:

pMemory = mmap(NULL, maxCapacity, 
    PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 

if (pMemory == MAP_FAILED) { 
    /* allocation failed */ 
} 
1

mmap rất hữu ích để chuẩn bị ánh xạ bộ nhớ bạn yêu cầu, nhưng nó không phân bổ nó cho chương trình của bạn. Hạt nhân sẽ quan tâm đến việc cấp phát bộ nhớ khi bạn truy cập vào bộ nhớ, do đó, có thể thực hiện mmap -ing 8 GB trên bộ nhớ 4GB, nếu bạn không truy cập đồng thời vào 8GB.

0

Trước tiên, bạn phải nói với Linux bạn muốn nó để làm cam kết kế toán:

echo "2" > /proc/sys/vm/overcommit_memory 

Nếu nó giữ mặc định di sản (từ khi Linux là một hệ điều hành đồ chơi) cho phép overcommit không giới hạn và làm cho ứng dụng của bạn khủng khiếp sụp đổ khi chúng hết bộ nhớ vật lý.

Ngoài ra, như những người khác đã nói, bạn cần phải kiểm tra giá trị trả lại của mmap đối với MAP_FAILED và không cần sử dụng mprotect. Chỉ cần chuyển đúng giá trị của PROT_* đến mmap để bắt đầu.

Các vấn đề liên quan