2010-10-01 19 views
98

Tất cả các chức năng được đề cập trong khối này là các hàm thư viện. Làm thế nào tôi có thể khắc phục sự rò rỉ bộ nhớ này?Rò rỉ có thể tiếp cận được phát hiện bởi Valgrind

Được liệt kê trong danh mục "Vẫn có thể truy cập". (Có 4 hơn, đó là rất giống nhau, nhưng kích thước khác nhau)

630 bytes in 1 blocks are still reachable in loss record 5 of 5 
    at 0x4004F1B: calloc (vg_replace_malloc.c:418) 
    by 0x931CD2: _dl_new_object (dl-object.c:52) 
    by 0x92DD36: _dl_map_object_from_fd (dl-load.c:972) 
    by 0x92EFB6: _dl_map_object (dl-load.c:2251) 
    by 0x939F1B: dl_open_worker (dl-open.c:255) 
    by 0x935965: _dl_catch_error (dl-error.c:178) 
    by 0x9399C5: _dl_open (dl-open.c:584) 
    by 0xA64E31: do_dlopen (dl-libc.c:86) 
    by 0x935965: _dl_catch_error (dl-error.c:178) 
    by 0xA64FF4: __libc_dlopen_mode (dl-libc.c:47) 
    by 0xAE6086: pthread_cancel_init (unwind-forcedunwind.c:53) 
    by 0xAE61FC: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126) 

Catch: Khi tôi chạy chương trình của tôi, nó đã không có rò rỉ bộ nhớ, nhưng nó có một dòng bổ sung trong đầu ra Valgrind, mà đã không được trình bày trước:

Syms thải sơn 0x5296fa0-0x52af438 trong /lib/libgcc_s-4.4.4-20100630.so.1 do munmap()

Nếu rò rỉ không thể được sửa chữa, có thể ai đó atleast giải thích tại sao munmap() dòng nguyên nhân Valgrind để báo cáo 0 "vẫn có thể truy cập" rò rỉ?

Edit:

Đây là một mẫu thử nghiệm tối thiểu:

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 

void *runner(void *param) { 
    /* some operations ... */ 
    pthread_exit(NULL); 
} 

int n; 

int main(void) { 

    int i; 
    pthread_t *threadIdArray; 

    n=10; /* for example */ 

    threadIdArray = malloc((n+n-1)*sizeof(pthread_t)); 

    for(i=0;i<(n+n-1);i++) { 
     if(pthread_create(&threadIdArray[i],NULL,runner,NULL) != 0) { 
      printf("Couldn't create thread %d\n",i); 
      exit(1); 
     } 
    } 


    for(i=0;i<(n+n-1);i++) { 
     pthread_join(threadIdArray[i],NULL); 
    } 

    free(threadIdArray); 

    return(0); 
} 

Run with:

valgrind -v --leak-check=full --show-reachable=yes ./a.out 

Trả lời

252

Có nhiều cách để xác định "rò rỉ bộ nhớ". Đặc biệt, có hai định nghĩa chính của "rò rỉ bộ nhớ" được sử dụng phổ biến giữa các lập trình viên.

Định nghĩa thường được sử dụng đầu tiên về "rò rỉ bộ nhớ" là "Bộ nhớ đã được cấp phát và sau đó không được giải phóng trước khi chương trình chấm dứt." Tuy nhiên, nhiều lập trình viên (đúng) cho rằng một số loại rò rỉ bộ nhớ nào đó phù hợp với định nghĩa này không thực sự gây ra bất kỳ vấn đề nào, và do đó không nên xem xét đúng sự cố "rò rỉ bộ nhớ".

Định nghĩa "rò rỉ bộ nhớ" chặt chẽ hơn (và hữu dụng hơn) là "Bộ nhớ được cấp phát và không thể sau đó được giải phóng vì chương trình không còn bất kỳ con trỏ nào đến khối bộ nhớ được cấp phát". Nói cách khác, bạn không thể giải phóng bộ nhớ mà bạn không còn có bất kỳ gợi ý nào. Do đó bộ nhớ như vậy là "rò rỉ bộ nhớ". Valgrind sử dụng định nghĩa khắt khe này về thuật ngữ "rò rỉ bộ nhớ". Đây là loại rò rỉ có khả năng gây ra sự suy giảm đáng kể đống, đặc biệt là đối với các quá trình lâu dài.

Danh mục "vẫn có thể truy cập" trong báo cáo rò rỉ của Valgrind đề cập đến phân bổ chỉ phù hợp với định nghĩa đầu tiên về "rò rỉ bộ nhớ". Những khối này không được giải phóng, nhưng chúng có thể được giải phóng (nếu lập trình viên muốn) bởi vì chương trình vẫn đang theo dõi các con trỏ tới các khối bộ nhớ đó.

Nói chung, không cần phải lo lắng về các khối "vẫn có thể truy cập". Chúng không gây ra vấn đề mà đúng rò rỉ bộ nhớ có thể gây ra. Ví dụ, thường không có tiềm năng cho sự cạn kiệt đống từ các khối "vẫn có thể truy cập". Điều này là do các khối này thường phân bổ một lần, các tham chiếu được lưu giữ trong suốt thời gian tồn tại của quá trình. Trong khi bạn có thể thực hiện và đảm bảo rằng chương trình của bạn giải phóng tất cả bộ nhớ được cấp phát, thường thì không có lợi ích thiết thực nào khi hệ điều hành sẽ thu hồi lại toàn bộ bộ nhớ của quá trình sau khi quá trình chấm dứt. Ngược lại điều này với đúng rò rỉ bộ nhớ, nếu không được cố định, có thể gây ra một quá trình hết bộ nhớ nếu chạy đủ lâu hoặc đơn giản là gây ra quá trình tiêu thụ bộ nhớ nhiều hơn mức cần thiết.

Có lẽ là lần duy nhất hữu ích để đảm bảo rằng tất cả phân bổ có "giải phóng" phù hợp là công cụ phát hiện rò rỉ của bạn không thể biết khối nào "vẫn có thể truy cập được" (nhưng Valgrind có thể thực hiện việc này) hoặc hệ điều hành của bạn không ' t đòi lại tất cả bộ nhớ của quá trình chấm dứt (tất cả các nền tảng mà Valgrind đã được chuyển để thực hiện việc này).

+0

bạn có thể phỏng đoán những gì munmap() đang làm mà làm cho "vẫn có thể truy cập" khối biến mất? –

+3

@crypto: Có thể là 'munmap' được gọi là kết quả của việc dỡ bỏ một đối tượng được chia sẻ. Và tất cả các tài nguyên được sử dụng bởi các đối tượng chia sẻ có thể được giải phóng trước khi nó được dỡ xuống. Điều này có thể giải thích lý do tại sao "vẫn có thể tiếp cận" được giải phóng trong trường hợp 'munmap'. Tôi chỉ suy đoán ở đây, mặc dù.Không có đủ thông tin ở đây để nói chắc chắn. –

+2

Một trường hợp bộ nhớ "vẫn có thể truy cập" có thể được coi là rò rỉ bộ nhớ: giả sử bạn có bảng băm nơi bạn thêm con trỏ vào bộ nhớ được cấp phát là giá trị. Nếu bạn tiếp tục chèn các mục nhập mới trên bảng, nhưng sẽ không xóa và giải phóng những mục bạn không cần nữa, nó có thể phát triển vô thời hạn, rò rỉ sự kiện bộ nhớ heap nếu bộ nhớ đó là "vẫn có thể truy cập". Đây là trường hợp rò rỉ bộ nhớ bạn có thể có trong Java hoặc các ngôn ngữ thu thập rác khác. – lvella

9

Bạn dường như không hiểu những gì still reachable phương tiện.

Bất cứ điều gì still reachablekhông rò rỉ. Bạn không cần phải làm bất cứ điều gì về nó.

+13

Điều này xung đột với các biện pháp khác do Valgrind cung cấp cũng như không chính xác về mặt kỹ thuật. Bộ nhớ là "vẫn có thể truy cập" ở lối ra chương trình và do đó có khả năng bị rò rỉ. Điều gì sẽ xảy ra nếu bạn đang gỡ lỗi mã để chạy trên một RTOS mà không làm sạch bộ nhớ tốt sau khi thoát khỏi chương trình? – Toymakerii

+4

Thật không may, đó không phải lúc nào cũng đúng. Ví dụ, các bộ mô tả tập tin bị mất có thể được tính là rò rỉ bộ nhớ, nhưng valgrind phân loại chúng là "vẫn có thể truy cập", có lẽ vì các con trỏ dẫn đến chúng vẫn có thể truy cập được trong một bảng hệ thống. Nhưng với mục đích gỡ lỗi, chẩn đoán thực sự là "rò rỉ bộ nhớ". – Cyan

+0

Mô tả tập tin bị mất là * không * rò rỉ bộ nhớ theo định nghĩa. Có lẽ bạn đang nói về con trỏ 'FILE' bị mất? –

10

Vì có một số thường lệ từ gia đình pthread ở phía dưới (nhưng tôi không biết cái nào cụ thể), tôi đoán là bạn đã khởi chạy một số chuỗi có thể tham gia đã chấm dứt thực thi.

Thông tin trạng thái thoát của chuỗi đó được lưu giữ cho đến khi bạn gọi pthread_join. Do đó, bộ nhớ được lưu giữ trong một bản ghi bị mất khi chấm dứt chương trình, nhưng nó vẫn có thể truy cập được vì bạn có thể sử dụng pthread_join để truy cập nó.

Nếu phân tích này là chính xác, hãy khởi chạy các chuỗi này tách ra hoặc tham gia trước khi chấm dứt chương trình của bạn.

Sửa: Tôi chạy chương trình mẫu của bạn (sau khi một số sự điều chỉnh rõ ràng) và tôi không có lỗi nhưng sau

==18933== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4) 
--18933-- 
--18933-- used_suppression:  2 dl-hack3-cond-1 
--18933-- used_suppression:  2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a 

Kể từ khi điều dl- giống phần lớn những gì bạn nhìn thấy tôi đoán rằng bạn xem một vấn đề đã biết có giải pháp về tệp nén cho valgrind. Có lẽ hệ thống của bạn không được cập nhật hoặc bản phân phối của bạn không duy trì những thứ này. (Mỏ là ubuntu 10.4, 64bit)

+0

Chủ đề không tham gia vào chuỗi chính. Tham khảo bản chỉnh sửa. –

+0

@crypto: xem chỉnh sửa của tôi –

+0

Tôi nhận được 0 lỗi giống như bạn. Vui lòng kiểm tra tóm tắt rò rỉ để biết thông tin về "rò rỉ". –

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