2012-08-29 32 views
6

Tôi đã chạy kiểm tra bộ nhớ qua đêm trên một hệ thống Linux nhúng. Sử dụng vmstat tôi đã quan sát thấy rằng bộ nhớ tự do đều giảm theo thời gian. Theo một số phân tích smaps trong procfs, quá trình của một quá trình phát triển ở cùng tốc độ. Tôi nghi ngờ một rò rỉ bộ nhớ và tìm thấy một vài điểm trong mã nơi newdelete được sử dụng thường xuyên. Tuy nhiên, tôi không thấy cuộc gọi new mà không khớp với các cuộc gọi delete.Nếu/Khi nào thì bộ nhớ heap được phân phối lại có được khai hoang?

tôi chạy kiểm tra bộ nhớ một lần nữa và sáng nay xóa cache bộ nhớ với các cuộc gọi sau

echo 3 > /proc/sys/vm/drop_caches 

Bộ nhớ miễn phí được liệt kê trong vmstat đi xuống đến một giá trị gần khi thử nghiệm đã được bắt đầu.

Hạt nhân có thường xuyên thu hồi các trang heap không sử dụng không? Nếu vậy, có những thời điểm nào khác ngoài thời gian trên mà việc này được thực hiện không? Có lẽ khi bộ nhớ miễn phí được dưới một ngưỡng nhất định?

+4

Bộ nhớ không sử dụng là bộ nhớ bị lãng phí, do đó, linux sử dụng bộ nhớ, cho đến khi người khác muốn sử dụng bộ nhớ đó. – PlasmaHH

+1

bạn đang nói về heap hạt nhân hoặc đống được sử dụng bởi quá trình này dường như bị rò rỉ? –

+0

@Tom: Tôi đang nói về đống quy trình không gian người dùng – waffleman

Trả lời

5

Như những người khác đã nói, đó là nhiệm vụ của quá trình trả lại bộ nhớ cho hạt nhân.

Thông thường có 2 cách để cấp phát bộ nhớ: nếu bạn malloc()/new một khối bộ nhớ trên một kích thước nhất định, bộ nhớ sẽ được cấp từ hệ điều hành qua mmap() và được miễn phí ngay sau khi hoàn toàn miễn phí. Các khối nhỏ hơn được phân bổ bằng cách tăng vùng dữ liệu của quá trình bằng cách dịch chuyển biên giới sbrk trở lên. Bộ nhớ này chỉ được giải phóng nếu một khối trên một kích thước nhất định là miễn phí ở cuối đoạn đó.

ví dụ .: (pseudo code, tôi không biết C++ rất tốt) Bản đồ

a = new char[1000]; 
b = new char[1000]; 

Memory:

---------------+---+---+ 
end of program | a | b | 
---------------+---+---+ 

Nếu bạn miễn phí a bây giờ, bạn có một lỗ ở giữa. Nó không được giải thoát bởi vì nó không thể được giải phóng. Nếu bạn miễn phí b, bộ nhớ của quá trình có thể hoặc không thể giảm; phần còn lại chưa sử dụng được trả lại cho hệ thống.

Một thử nghiệm với một chương trình đơn giản như

#include <stdlib.h> 

int main() 
{ 
    char * a = malloc(100000); 
    char * b = malloc(100000); 
    char * c = malloc(100000); 
    free(c); 
    free(b); 
    free(a); 
} 

dẫn đến một đầu ra strace như

brk(0)         = 0x804b000 
brk(0x8084000)       = 0x8084000 
brk(0x80b5000)       = 0x80b5000 
brk(0x809c000)       = 0x809c000 
brk(0x8084000)       = 0x8084000 
brk(0x806c000)       = 0x806c000 

là cho thấy rằng giá trị brk là lần đầu tiên tăng (đối với malloc()) và sau đó giảm trở lại (cho free()).

+0

thư viện thời gian chạy nào? –

+0

@TomTanner, glibc thực hiện quản lý bộ nhớ trên Linux. –

+0

Một chương trình có thực sự giảm kích thước của nó thông qua 'sbrk' không? Tôi luôn luôn giả định rằng vì cơ hội có một khối hoàn toàn miễn phí ở cuối quá thấp đến mức nó sẽ không bao giờ làm giảm kích thước. –

1

Hạt nhân sẽ xác nhận lại các trang bộ nhớ được lưu trong bộ nhớ cache khi cần chúng, tức là khi hệ thống sẽ hết bộ nhớ. cho dù các trang bộ nhớ từ đống của quy trình (lưu trữ miễn phí) có bao giờ được trả lại cho hệ điều hành hay không theo quyết định của trình quản lý bộ nhớ của quá trình, trong trường hợp này là việc triển khai new/delete trong thư viện C++. Đây là một hoạt động hoàn toàn tự nguyện mà hạt nhân không có gì để làm.

Từ thực tế là drop_caches đã thực hiện thủ thuật, bạn có thể suy ra rằng đó là bộ đệm hạt nhân, không phải là quá trình lưu trữ, đã lấp đầy bộ nhớ. Sử dụng lệnh free để tìm hiểu xem có bao nhiêu bộ nhớ thực sự có sẵn để sử dụng ứng dụng, đặc biệt là. dòng -/+ buffers/cache nó báo cáo.

1

Gọi delete trong chương trình của bạn khiến bộ nhớ quay trở lại trình quản lý bộ nhớ là một phần của thời gian chạy chương trình của bạn. Về nguyên tắc, điều này có thể được viết để trả lại bộ nhớ tự do cho hệ điều hành, nhưng tôi sẽ ngạc nhiên nếu nó đã làm. Thay vào đó, bộ nhớ tái chế được giữ sang một bên cho các cuộc gọi tiếp theo đến new.

Lưu ý rằng đây là bộ nhớ ảo của quy trình của bạn; bao nhiêu của nó là thực sự cư trú trong bộ nhớ vật lý bất cứ lúc nào trong quá trình thực hiện chương trình phụ thuộc vào tải hệ thống tổng thể và được xử lý bởi hệ điều hành.

0

Cuộc gọi của người dùng tới malloc và miễn phí (hoặc mới và xóa), theo hiểu biết tốt nhất của tôi không bao giờ trả lại các trang không còn được sử dụng cho O/S nữa. Thay vào đó, họ chỉ nhớ những gì bộ nhớ đã được giải phóng để nếu bạn làm một malloc/mới của một kích thước có thể được hài lòng bởi bộ nhớ giải phóng trước đó, sau đó nó sẽ sử dụng, thay vì đi đến O/S và sử dụng sbrk để có được nhiều bộ nhớ hơn.

Như vậy mã này:

for (;;) 
{ 
    struct { char data[200 * 1024 * 1024] } HugeBuffer; 
    HugeBuffer *buff = new HugeBuffer; 
    delete buff; 
} 

sẽ phân bổ 200 MB một lần, và sau đó chỉ cần đều đặn sử dụng bộ nhớ rằng mãi mãi. Nó sẽ đi đến O/S một lần trên phân bổ ban đầu, và sau đó vòng lặp fiddling xung quanh trong không gian người dùng.

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