[英]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
,您可以在此處找到所有相關標志。
每個由 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.