2009-11-19 22 views
24

Sau nhiều năm làm việc trên một thư viện C++ đa năng sử dụng trình biên dịch Microsoft MSVC trong Visual Studio, chúng tôi đang chuyển nó sang Linux/Mac OS X (cầu nguyện cho chúng tôi). Tôi đã trở nên quen thuộc và khá thích cơ chế phát hiện rò rỉ bộ nhớ đơn giản trong MSVC:Phát hiện rò rỉ bộ nhớ GCC tương đương với Microsoft crtdbg.h?

#ifdef DEBUG 
    #define _CRTDBG_MAP_ALLOC 
    #define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) 
    #include <stdlib.h> 
    #include <crtdbg.h> 
#else 
    #define NEW new 
#endif 

Mọi phân bổ bộ nhớ được thực hiện bằng macro MỚI này. Bất cứ khi nào một quá trình sử dụng thư viện của chúng tôi chấm dứt, mọi rò rỉ bộ nhớ (các khối không được phân bổ) được báo cáo trên bàn điều khiển cùng với tệp và dòng # nơi bộ nhớ ban đầu được cấp phát.

Phần về điều này mà tôi thích là tôi không phải chủ động "chạy với công cụ hiệu suất" hoặc nói cách khác là tôi đang tìm kiếm sự rò rỉ. Rò rỉ được báo cáo cho tôi trong quá trình phát triển thông thường, mỗi khi quá trình chấm dứt.

Bây giờ chúng ta đang chuyển sang thế giới GCC, tôi thấy rằng các công cụ phát hiện rò rỉ bộ nhớ, nhiều công cụ khá phức tạp, yêu cầu tôi chỉ rõ rằng tôi đang ở chế độ tìm kiếm bị rò rỉ. IDE của tôi là Xcode và tôi đã xem xét một số công cụ phát hiện phân bổ/rò rỉ (như Instruments và MallocDebug) nhưng tôi thừa nhận tôi đã không dành thời gian để thu hút đầu tôi hoàn toàn. Tôi tiếp tục bị sa thải bởi thực tế rằng tôi thực sự phải xác định rằng tôi đang tìm kiếm một rò rỉ trước thời hạn, thay vì được cảnh báo với nó tự động.

Tôi đang sử dụng Xcode 3.2 và tôi nghe rằng hiện có tích hợp tiện lợi với công cụ phân tích tĩnh, nhưng một lần nữa tôi chưa xem xét điều này. Tôi đang tìm một số ý tưởng về những lựa chọn của tôi. Có cơ chế so sánh được tích hợp vào GCC và/hoặc Xcode không? Có một thư viện hoặc công cụ bên thứ ba đơn giản nào thực hiện chức năng cơ bản mà tôi biết và yêu thích không? Hay tôi nên mút nó lên và học cách làm mới?

Trả lời

15

Bạn nên xem "Cross-Platform Memory Leak Detector", trông rất giống với kỹ thuật crtdbg.h.

+0

Chính xác những gì tôi đang tìm kiếm, cảm ơn bạn! –

+0

tìm đẹp ... +1 cho câu hỏi và câu trả lời. – Nicholaz

4

Có lẽ bạn có thể sử dụng Boehm garbage collector như một công cụ phát hiện rò rỉ:

http://www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html

Từ trang web:

#include "leak_detector.h" 

main() { 
    int *p[10]; 
    int i; 
    /* GC_find_leak = 1; for new collector versions not  */ 
    /* compiled with -DFIND_LEAK.    */ 
    for (i = 0; i < 10; ++i) { 
    p[i] = malloc(sizeof(int)+i); 
    } 
    for (i = 1; i < 10; ++i) { 
    free(p[i]); 
    } 
    for (i = 0; i < 9; ++i) { 
    p[i] = malloc(sizeof(int)+i); 
    } 
    CHECK_LEAKS(); 
} 

(bạn nhận được thông báo qua stderr)

+0

Cảm ơn đề xuất. Tôi đã không thể xây dựng thành công Boehm gc (phiên bản 6.8) trong Mac OS X, và đọc tài liệu cho thấy một số gotchas đáng sợ (hỗ trợ đa luồng có vấn đề, hỗ trợ C++ có vấn đề), giúp tôi tránh xa điều này. –

3

Tôi không nhận thức được bất cứ điều gì "được xây dựng trong" mà làm những gì bạn mô tả, nhưng nó không có vẻ như nó sẽ rất khó để "cuộn của riêng bạn" phiên bản o f này. Bạn chỉ muốn sửa lỗi mới của bạn để ghi lại con trỏ, tệp và dòng trong một map<void*, AllocationInfo> trong đó khóa là con trỏ được cấp phát và giá trị (AllocationInfo) sẽ là một số cấu trúc giữ tên tệp, số dòng, v.v. Bạn cũng cần xác định nhà điều hành xóa tùy chỉnh kiểm tra bản đồ cho con trỏ bị xóa. Nếu được tìm thấy, mục nhập đó sẽ bị xóa khỏi bản đồ. Sau đó, tại thời gian tắt máy, bạn phát ra nội dung của bản đồ.

Tôi tìm thấy a page where someone describes their own home-grown system that works like this.

+0

Cảm ơn lời khuyên ... Tôi đang đưa ra một phát bắn ngay bây giờ. –

19

Bạn có một số tùy chọn có sẵn cho bạn.

Đầu tiên và phổ biến nhất, bạn có thể chạy ứng dụng của mình dưới các công cụ như Valgrind. Điều đó sẽ chỉ cho bạn một số sự lạm dụng bộ nhớ, chẳng hạn như con trỏ NULL đọc và ghi và rò rỉ bộ nhớ. Có một số công cụ có sẵn trong bộ Valgrind, vì vậy hãy chắc chắn kiểm tra chúng.

Thứ hai, bạn luôn có thể sử dụng thư viện sử dụng mẹo LD_PRELOAD.Về cơ bản, thủ thuật LD_PRELOAD cho phép tiêm DLL, có nghĩa là các công cụ có thể được tạo ra để giúp theo dõi việc sử dụng bộ nhớ của bạn trong ứng dụng mà không thay đổi bất cứ thứ gì. Bạn sẽ tìm thấy các công cụ như dmallocefence để được khá rộng rãi trong các cơ sở gỡ lỗi mà họ cung cấp.

Cuối cùng, các bản phát hành GCC gần đây bao gồm một công cụ có tên là Mudflap. Điều này về cơ bản sử dụng các thiết bị chức năng để bọc các cuộc gọi xung quanh cùng một chức năng bộ nhớ mà dmalloc, efence, và Valgrind. Chương trình sẽ chậm hơn đáng kể và có thể được điều chỉnh khi chạy, mặc dù nó vẫn có vẻ như nó có nhiều tiềm năng.

Tôi đã sử dụng cả ba và thấy Valgrind rất hữu ích. Tôi cũng rất thích sử dụng Mudflap, mặc dù tôi vẫn chưa thể.

+0

+1 cho Valgrind. Các đường cong học tập là một chút dốc đầu tiên, nhưng nó tuyệt vời không phải biên dịch lại. – Matthew

+0

Dường như Mudflap là C và "rất đơn giản C++" ngay bây giờ, mà tôi khá chắc chắn sẽ loại trừ thư viện C++ của chúng tôi. Valgrind trông có vẻ hứa hẹn hơn, nhưng sau đó bạn sẽ luôn chạy cấu hình DEBUG của bạn dưới Valgrind, hoặc bạn thường chỉ chạy nó dưới Valgrind "một lần trong một thời gian" khi tìm kiếm rò rỉ và các lỗi bộ nhớ khác? Tôi nhận ra bạn có thể làm một trong hai, nhưng cách tiếp cận của bạn là gì? –

+1

Tôi thường chạy Valgrind trước các mốc quan trọng, chẳng hạn như các cuộc biểu tình hoặc các trạm kiểm soát phát triển. Tôi làm điều này bởi vì bất kỳ vấn đề bộ nhớ nào bị cắt lên kể từ cột mốc cuối cùng sẽ vẫn ở đó và sẽ rất tốt khi được làm sạch trong mỗi mốc quan trọng. Chạy nó tất cả các thời gian phụ thuộc vào những gì tập trung của bạn là trong quá trình phát triển (hiệu suất so với rò rỉ bí truyền).Điều quan trọng là bạn phát triển ý nghĩa của công cụ; sẽ có những thứ mà bạn phải ngăn chặn và những thứ phải được giải quyết ngay lập tức. – s1n

8

Bạn cũng có thể tìm thấy biến môi trường MALLOC_CHECK_ hữu ích.

Từ malloc (3) xem man page:

các phiên bản gần đây của Linux libc (chậm nhất là 5.4.23) và glibc (2.x) bao gồm thực hiện malloc() là du dương qua biến môi trường. Khi MALLOC_CHECK_ được thiết lập, một thực thi đặc biệt (ít hiệu quả) được sử dụng được thiết kế để khoan dung với các lỗi đơn giản, chẳng hạn như các cuộc gọi kép miễn phí() với cùng một đối số, hoặc tràn ngập một byte đơn (các lỗi off-by-one)). Không phải tất cả các lỗi như vậy có thể được bảo vệ chống lại, tuy nhiên, và rò rỉ bộ nhớ có thể xảy ra. Nếu MALLOC_CHECK_ được đặt thành 0, mọi tham chiếu heap được phát hiện bị bỏ qua âm thầm; nếu được đặt thành 1, thông báo chẩn đoán sẽ được in trên stderr; nếu đặt thành 2, hủy bỏ (3) được gọi ngay lập tức; nếu được đặt thành 3, thông báo chẩn đoán được in trên stderr và chương trình bị hủy. Việc sử dụng giá trị MALLOC_CHECK_ khác không có thể hữu ích vì nếu không sự cố có thể xảy ra sau này, và nguyên nhân thực sự của vấn đề là rất khó để theo dõi.

3

Tôi gặp sự cố tương tự khi chúng tôi bắt đầu chuyển sang máy Mac. "Chạy với công cụ hiệu suất -> Rò rỉ" là chỉ tôi tìm thấy và tôi ít hơn vui mừng bởi nó ... ít nhất là so với CRTDEBUG. Tôi hiểu có một số tùy chọn (như được mô tả bởi những người khác ở đây), nhưng cuối cùng kể từ khi chúng tôi là nền tảng đa, chúng tôi đang sử dụng Windows để tìm kiếm các rò rỉ.

Vì bạn đề cập đến máy phân tích tĩnh. Chúng tôi đã dành thời gian cố gắng tìm ra nóng để chạy nó cho đến khi chúng tôi thấy rằng nó chỉ có C nhưng không phải C++

+0

Đó chính xác là trải nghiệm của tôi cho đến nay. –