2016-07-28 22 views
5

Một số chương trình mà tôi hiện đang làm việc để tiêu thụ nhiều bộ nhớ hơn tôi nghĩ. Vì vậy, tôi đang cố gắng để hiểu làm thế nào glibc malloc cắt tỉa hoạt động. Tôi đã viết bài kiểm tra sau:Tìm hiểu về cắt tỉa glibc malloc

#include <malloc.h> 
#include <unistd.h> 

#define NUM_CHUNKS 1000000 
#define CHUNCK_SIZE 100 

int main() 
{ 
    // disable fast bins 
    mallopt(M_MXFAST, 0); 

    void** array = (void**)malloc(sizeof(void*) * NUM_CHUNKS); 

    // allocating memory 
    for(unsigned int i = 0; i < NUM_CHUNKS; i++) 
    { 
     array[i] = malloc(CHUNCK_SIZE); 
    } 

    // releasing memory ALMOST all memory 
    for(unsigned int i = 0; i < NUM_CHUNKS - 1 ; i++) 
    { 
     free(array[i]); 
    } 

    // when enabled memory consumption reduces 
    //int ret = malloc_trim(0); 
    //printf("ret=%d\n", ret); 

    malloc_stats(); 

    sleep(100000); 
} 

đầu ra thử nghiệm (mà không gọi malloc_trim):

Arena 0: 
system bytes  = 112054272 
in use bytes  =  112 
Total (incl. mmap): 
system bytes  = 120057856 
in use bytes  = 8003696 
max mmap regions =   1 
max mmap bytes = 8003584 

Mặc dù hầu hết các bộ nhớ đã được phát hành, mã kiểm tra này tiêu thụ bộ nhớ nhiều cư dân hơn mong đợi:

[[email protected]]# ps aux | grep test 
root  14662 1.8 0.4 129736 **118024** pts/10 S 20:19 0:00 ./test 

Xử lý smaps:

0245e000-08f3b000 rw-p 00000000 00:00 0         [heap] 
Size:    109428 kB 
Rss:    109376 kB 
Pss:    109376 kB 
Shared_Clean:   0 kB 
Shared_Dirty:   0 kB 
Private_Clean:   0 kB 
Private_Dirty: 109376 kB 
Referenced:  109376 kB 
Anonymous:  109376 kB 
AnonHugePages:   0 kB 
Swap:     0 kB 
KernelPageSize:  4 kB 
MMUPageSize:   4 kB 
Locked:    0 kB 
VmFlags: rd wr mr mw me ac 
7f1c60720000-7f1c60ec2000 rw-p 00000000 00:00 0 
Size:    7816 kB 
Rss:    7816 kB 
Pss:    7816 kB 
Shared_Clean:   0 kB 
Shared_Dirty:   0 kB 
Private_Clean:   0 kB 
Private_Dirty:  7816 kB 
Referenced:   7816 kB 
Anonymous:   7816 kB 
AnonHugePages:   0 kB 
Swap:     0 kB 
KernelPageSize:  4 kB 
MMUPageSize:   4 kB 
Locked:    0 kB 

Khi tôi cho phép các cuộc gọi đến malloc_trim đầu ra của thử nghiệm vẫn được gần như giống nhau:

ret=1 
Arena 0: 
system bytes  = 112001024 
in use bytes  =  112 
Total (incl. mmap): 
system bytes  = 120004608 
in use bytes  = 8003696 
max mmap regions =   1 
max mmap bytes = 8003584 

Tuy nhiên, RSS giảm đáng kể:

[[email protected]]# ps aux | grep test 
root  15733 0.6 0.0 129688 **8804** pts/10 S 20:20 0:00 ./test 

Process smaps (sau malloc_trim):

01698000-08168000 rw-p 00000000 00:00 0         [heap] 
Size:    109376 kB 
Rss:     8 kB 
Pss:     8 kB 
Shared_Clean:   0 kB 
Shared_Dirty:   0 kB 
Private_Clean:   0 kB 
Private_Dirty:   8 kB 
Referenced:   8 kB 
Anonymous:    8 kB 
AnonHugePages:   0 kB 
Swap:     0 kB 
KernelPageSize:  4 kB 
MMUPageSize:   4 kB 
Locked:    0 kB 
VmFlags: rd wr mr mw me ac 
7f508122a000-7f50819cc000 rw-p 00000000 00:00 0 
Size:    7816 kB 
Rss:    7816 kB 
Pss:    7816 kB 
Shared_Clean:   0 kB 
Shared_Dirty:   0 kB 
Private_Clean:   0 kB 
Private_Dirty:  7816 kB 
Referenced:   7816 kB 
Anonymous:   7816 kB 
AnonHugePages:   0 kB 
Swap:     0 kB 
KernelPageSize:  4 kB 
MMUPageSize:   4 kB 
Locked:    0 kB 

Sau khi gọi malloc_trim, đống đã bị ngắt. Tôi cho rằng phân đoạn mmap 8MB vẫn có sẵn do phần cuối của bộ nhớ không được phát hành.

Tại sao trang web heap không được thực hiện tự động bởi malloc? Có cách nào để cấu hình malloc như vậy mà cắt tỉa sẽ được thực hiện tự động (khi nó có thể tiết kiệm được nhiều bộ nhớ)?

Tôi đang sử dụng phiên bản glibc 2.17.

+0

Nếu bạn đang sử dụng nhiều bộ nhớ và cần được xử lý theo những cách cụ thể, tôi khuyên bạn nên tự mình sử dụng 'mmap' trên POSIX và' VirtualAlloc' trên Windows. –

Trả lời

4

Vì lý do lịch sử, bộ nhớ cho phân bổ nhỏ đến từ một hồ bơi được quản lý với cuộc gọi hệ thống brk. Đây là một cuộc gọi hệ thống rất cũ - ít nhất là cũ như Version 6 Unix - và điều duy nhất nó có thể làm là thay đổi kích thước của một "đấu trường" có vị trí trong bộ nhớ được cố định. Điều đó có nghĩa là, các hồ bơi brk không thể thu nhỏ quá khứ một khối vẫn được phân bổ.

Chương trình của bạn phân bổ N khối bộ nhớ và sau đó deallocates N-1 trong số chúng. Khối duy nhất không phân phối lại là một khối nằm ở địa chỉ cao nhất. Đó là kịch bản trường hợp xấu nhất cho brk: không thể giảm kích thước, mặc dù 99,99% hồ bơi không được sử dụng! Nếu bạn thay đổi chương trình của mình để chặn không miễn phí là array[0] thay vì array[NUM_CHUNKS-1], bạn sẽ thấy cả không gian địa chỉ RSS và thu nhỏ khi cuộc gọi cuối cùng đến free.

Khi bạn gọi rõ ràng malloc_trim, nó cố gắng giải quyết giới hạn này bằng cách sử dụng phần mở rộng Linux, madvise(MADV_DONTNEED), giải phóng RAM vật lý chứ không phải không gian địa chỉ (như bạn đã quan sát). Tôi không biết tại sao điều này chỉ xảy ra khi có cuộc gọi rõ ràng tới malloc_trim.

Ngẫu nhiên, phân đoạn mmap 8MB dành cho phân bổ ban đầu của bạn là array.

+0

Cảm ơn bạn đã trả lời! Tôi thấy rằng 'mảng' thực sự nằm trên phân đoạn 8MB, và tôi cũng thấy rằng' mảng [N-1] 'nằm ở ** cuối ** của phân đoạn heap. Nếu nó là ở phần cuối của nó, bây giờ tôi không hiểu làm thế nào nó có thể được cắt (khi gọi 'malloc_trim'). – michael

+0

Đọc những gì tôi đã nói về 'madvise' một lần nữa ... – zwol

+0

Tôi hiểu, cảm ơn bạn. Có cách nào để tôi giảm lượng bộ nhớ RSS được tiêu thụ không? Bên cạnh đó gọi 'malloc_trim' mọi lúc rồi? – michael

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