簡體   English   中英

有沒有辦法驗證我的程序沒有 memory 泄漏?

[英]Is there way to verify my program has no memory leaks?

我想確定以下程序(查找最大子數組的實現)是否泄漏 memory。 有沒有一種通用的方法來確定這一點? 例如使用調試器的某些功能? 什么是一般策略?

struct Interval {
   int max_left;
   int max_right;
   int sum;
};

struct Interval * max_crossing_subarray(int A[], int low, int mid, int high) {
    struct Interval * crossing = malloc(sizeof(struct Interval));

    int left_sum = INT_MIN;
    int sum = 0;

    for(int i = mid; i >= low; --i) {
        sum = sum + A[i];
        if(sum > left_sum) {
            left_sum = sum;
            crossing->max_left = i;
        }
    }

    int right_sum = INT_MIN;
    sum = 0;

    for(int j = mid+1; j <= high; ++j) {
        sum = sum + A[j];
        if(sum > right_sum) {
            right_sum = sum;
            crossing->max_right = j;
        }
    }

    crossing->sum = left_sum + right_sum;

    return crossing;
}

struct Interval * max_subarray(int A[], int low, int high) {
    if(high == low) {
        struct Interval * base = malloc(sizeof(struct Interval));
        *base = (struct Interval) { low, high, A[low] };
        return base;
    } else {
        int mid = floor((low+high)/2);
        struct Interval * left = malloc(sizeof(struct Interval));
        struct Interval * right = malloc(sizeof(struct Interval));
        left = max_subarray(A, low, mid);
        right = max_subarray(A, mid+1, high);
        struct Interval * cross = max_crossing_subarray(A, low, mid, high);
        if(left->sum >= right->sum & right->sum >= cross->sum) {
            free(right);
            free(cross);
            return left;
        } else if(right->sum >= left->sum & right->sum >= cross-> sum) {
            free(left);
            free(cross);
            return right;
        } else {
            free(left);
            free(right);
            return cross;
        }
    }
}

int main()
{
    int A[] = {-10, 7, -5, -3, 40, 4, -1, 8, -3, -1, -5, 20, 7};
    struct Interval * result = max_subarray(A, 0, 12);

    printf("left: %i, right: %i, sum: %i\n", result->max_left, result->max_right, result->sum);

    return 0;
}

由於程序的遞歸性質,它很難理解(至少對我來說)。 我想我已經把所有東西都塞住了,但我想找到一種方法來確定。

編輯所選答案中建議的軟件允許我找到所有泄漏,並且正如評論中指出的那樣,沒有理由分配左右,下面是 memory 無泄漏代碼。

struct Interval {
   int max_left;
   int max_right;
   int sum;
};

struct Interval * max_crossing_subarray(int A[], int low, int mid, int high) {
    struct Interval * crossing = malloc(sizeof(struct Interval));

    int left_sum = INT_MIN;
    int sum = 0;

    for(int i = mid; i >= low; --i) {
        sum = sum + A[i];
        if(sum > left_sum) {
            left_sum = sum;
            crossing->max_left = i;
        }
    }

    int right_sum = INT_MIN;
    sum = 0;

    for(int j = mid+1; j <= high; ++j) {
        sum = sum + A[j];
        if(sum > right_sum) {
            right_sum = sum;
            crossing->max_right = j;
        }
    }

    crossing->sum = left_sum + right_sum;

    return crossing;
}

struct Interval * max_subarray(int A[], int low, int high) {
    if(high == low) {
        struct Interval * base = malloc(sizeof(struct Interval));
        *base = (struct Interval) { low, high, A[low] };
        return base;
    } else {
        int mid = floor((low+high)/2);
        struct Interval * left = max_subarray(A, low, mid);
        struct Interval * right = max_subarray(A, mid+1, high);
        struct Interval * cross = max_crossing_subarray(A, low, mid, high);
        if(left->sum >= right->sum & right->sum >= cross->sum) {
            free(right);
            free(cross);
            return left;
        } else if(right->sum >= left->sum & right->sum >= cross-> sum) {
            free(left);
            free(cross);
            return right;
        } else {
            free(left);
            free(right);
            return cross;
        }
    }
}

int main()
{
    int A[] = {-10, 7, -5, -3, 40, 4, -1, 8, -3, -1, -5, 20, 7};
    struct Interval * result = max_subarray(A, 0, 13-1);

    printf("left: %i, right: %i, sum: %i\n", result->max_left, result->max_right, result->sum);

    return 0;
}

您可以使用valgrind It's a memory debugging tool for Linux and other UNIX-like systems that finds memory leaks as well as invalid memory accesses.

當我通過 valgrind 運行此代碼時,它會輸出以下內容:

[dbush@db-centos7 ~]$ valgrind ./x1
==3406== Memcheck, a memory error detector
==3406== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3406== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==3406== Command: ./x1
==3406== 
left: 4, right: 12, sum: 69
==3406== 
==3406== HEAP SUMMARY:
==3406==     in use at exit: 300 bytes in 25 blocks
==3406==   total heap usage: 49 allocs, 24 frees, 588 bytes allocated
==3406== 
==3406== LEAK SUMMARY:
==3406==    definitely lost: 300 bytes in 25 blocks
==3406==    indirectly lost: 0 bytes in 0 blocks
==3406==      possibly lost: 0 bytes in 0 blocks
==3406==    still reachable: 0 bytes in 0 blocks
==3406==         suppressed: 0 bytes in 0 blocks
==3406== Rerun with --leak-check=full to see details of leaked memory
==3406== 
==3406== For counts of detected and suppressed errors, rerun with: -v
==3406== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

所以你有一些泄漏。 現在讓我們通過--leak-check=full選項來查看這些泄漏的確切位置:

==11531== Memcheck, a memory error detector
==11531== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11531== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==11531== Command: ./x1
==11531== 
left: 4, right: 12, sum: 69
==11531== 
==11531== HEAP SUMMARY:
==11531==     in use at exit: 300 bytes in 25 blocks
==11531==   total heap usage: 49 allocs, 24 frees, 588 bytes allocated
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 1 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 2 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 3 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 4 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 5 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 6 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 7 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 8 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 9 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 10 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 11 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 12 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 13 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 14 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 15 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 16 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 17 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 18 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 19 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 20 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 21 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 22 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 23 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007A8: max_subarray (x1.c:49)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 24 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x4007B6: max_subarray (x1.c:50)
==11531==    by 0x4007CE: max_subarray (x1.c:51)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x4007E9: max_subarray (x1.c:52)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== 12 bytes in 1 blocks are definitely lost in loss record 25 of 25
==11531==    at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==11531==    by 0x40065B: max_crossing_subarray (x1.c:13)
==11531==    by 0x400802: max_subarray (x1.c:53)
==11531==    by 0x400931: main (x1.c:73)
==11531== 
==11531== LEAK SUMMARY:
==11531==    definitely lost: 300 bytes in 25 blocks
==11531==    indirectly lost: 0 bytes in 0 blocks
==11531==      possibly lost: 0 bytes in 0 blocks
==11531==    still reachable: 0 bytes in 0 blocks
==11531==         suppressed: 0 bytes in 0 blocks
==11531== 
==11531== For counts of detected and suppressed errors, rerun with: -v
==11531== ERROR SUMMARY: 25 errors from 25 contexts (suppressed: 0 from 0)

大多數泄漏來自以下兩條線:

    struct Interval * left = malloc(sizeof(struct Interval));
    struct Interval * right = malloc(sizeof(struct Interval));

如果我們看看接下來的兩行,很明顯為什么:

    left = max_subarray(A, low, mid);
    right = max_subarray(A, mid+1, high);

因此,在您將分配的 memory 的地址分配給這些指針之后,您會用其他值覆蓋這些地址,從而導致泄漏。 這可以通過擺脫malloc調用並使用 function 調用的結果進行初始化來解決:

    struct Interval * left = max_subarray(A, low, mid);
    struct Interval * right = max_subarray(A, mid+1, high);

最后一個在max_crossing_subarray

struct Interval * crossing = malloc(sizeof(struct Interval));

這個指針是從function返回的,所以我們需要看看丟失的free在哪里。 環顧四周,我們看到它是從max_subarray調用的,它最終將它作為result返回給main

struct Interval * result = max_subarray(A, 0, 13-1);

printf("left: %i, right: %i, sum: %i\n", result->max_left, result->max_right, result->sum);

return 0;

但是正如你所看到的,這里沒有調用free ,所以讓我們添加它:

struct Interval * result = max_subarray(A, 0, 13-1);

printf("left: %i, right: %i, sum: %i\n", result->max_left, result->max_right, result->sum);

free(result);
return 0;

現在,在進行這些修復之后,我們將再次運行 valgrind:

==11736== Memcheck, a memory error detector
==11736== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11736== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==11736== Command: ./x1
==11736== 
left: 4, right: 12, sum: 69
==11736== 
==11736== HEAP SUMMARY:
==11736==     in use at exit: 0 bytes in 0 blocks
==11736==   total heap usage: 25 allocs, 25 frees, 300 bytes allocated
==11736== 
==11736== All heap blocks were freed -- no leaks are possible
==11736== 
==11736== For counts of detected and suppressed errors, rerun with: -v
==11736== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

並且泄漏消失了。

一般來說,除非您將語言限制為功能較少的子語言(如 misra),否則您無法證明程序的正確性。 一般來說,這個問題是無法確定的。

但是您可以使用 lint 之類的軟件進行 static 檢查數學模式,或使用 valgrind 進行動態檢查,或者像 Coq 這樣的語言,其中程序是證明,並且它們使用 Hoare 邏輯來對您的代碼進行陳述。 例如,使用 Hoare 邏輯,證明 Windows 的 kernel 不會出現段錯誤。

除了已經提到的檢測器,包括最突出的valgrind ,您還可以使用AddressSanitizer工具,該工具集成了LeakSanitizer並在GCC自 4.8 版和Clang自 3.1 版以來實現。

相應的編譯器標志是-fsanitize=address-fsanitize=leak

此外,您可以使用MemorySanitizer來嘗試讀取未初始化的數據。


對於gcc ,您可以在此處找到所有相關標志。

https://clang.llvm.org/docs/AddressSanitizer.html

如何將 AddressSanitizer 與 GCC 一起使用?

每個由 malloc 結構分配的結構都必須在程序的所有情況下由 free 釋放。 因此,在所有情況下,您都會返回一個 Interval 實例。 您必須在主塊中釋放它。 或者您可以使用智能指針/分配器。 您還可以為 Interval 實現 operator =,並使用實例而不是指針。 為了快速分配返回值,您可以使用 std::swap

Intreval & operator=(Intreval && a)
{
    std::swap(a.max_left,max_left);
    std::swap(a.max_rignt,max_rignt);
    std::swap(a.sum,sum);
    return *this;
}

最后,如果您不是舒爾,請不要使用 malloc。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM