首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> C 語言問答

C++ 歸併排序記憶體洩漏分析:new[] 未配對 delete[] 導致 heap leak

     編輯:C 語言問答

問題代碼片段

void MergeSort(int a[], int n) {
    int *b = new int[n];  // 動態配置暫存陣列
    int s = 1;
    while (s < n) {
        MergePass(a, b, s, n);
        s += s;
        MergePass(b, a, s, n);
        s += s;
    }
    // 缺少 delete[] b;  → 記憶體洩漏!
}

洩漏原因分析

階段狀態
函式進入b 指向堆上新配置的 n * sizeof(int) 位元組
函式執行使用 b 作為歸併暫存區,邏輯正確
函式返回b 區域變數銷毀,但堆上記憶體未釋放,產生洩漏
程式結束OS 回收進程記憶體,但長期運行程式會累積耗盡記憶體

修正方案

方法一:函式結束前釋放(最簡單)

void MergeSort(int a[], int n) {
    int *b = new int[n];
    int s = 1;
    while (s < n) {
        MergePass(a, b, s, n);
        s += s;
        MergePass(b, a, s, n);
        s += s;
    }
    delete[] b;  // 關鍵:配對釋放
}

方法二:RAII 智慧指標(現代 C++ 風格)


#include 

void MergeSort(int a[], int n) {
    std::unique_ptr b(new int[n]);  // 自動釋放
    int s = 1;
    while (s < n) {
        MergePass(a, b.get(), s, n);
        s += s;
        MergePass(b.get(), a, s, n);
        s += s;
    }
    // 離開作用域自動 delete[]
}

方法三:std::vector(推薦,最安全簡潔)


#include 

void MergeSort(int a[], int n) {
    std::vector b(n);  // 自動管理記憶體
    int s = 1;
    while (s < n) {
        MergePass(a, b.data(), s, n);
        s += s;
        MergePass(b.data(), a, s, n);
        s += s;
    }
}

記憶體洩漏檢測工具

工具平台用法輸出範例
ValgrindLinux/macOSvalgrind --leak-check=full ./progdefinitely lost: 40 bytes in 1 blocks
AddressSanitizer (ASan)GCC/Clanggcc -fsanitize=address -g prog.cDirect leak of 40 byte(s) in 1 object(s)
Visual Studio CRTWindows_CrtDumpMemoryLeaks()Detected memory leaks! {123} normal block at 0x...
Dr. MemoryWindows/Linuxdrmemory -- prog.exe類似 Valgrind

NVWA 除錯工具使用說明

使用者提到的 NVWA (New Version of Wu's Allocator) 包含 debug_new.cpp:

// 編譯連結
g++ your_code.cpp debug_new.cpp -o your_prog
// 執行
./your_prog
// 若有洩漏,程式結束時輸出類似:
// Leaked memory at address 0x... size 40 bytes allocated from your_code.cpp:123

使用者遇到的「加上 delete[] 後無法運行」問題分析

可能原因檢查方法
delete[] 位置錯誤(提前釋放)確認 delete[] b; 在 所有使用 b 之後、函式返回前
重複釋放檢查是否有其他地方也 delete[] b
b 被修改(指標偏移)確保 b 指向原始配置位址,未做 b++ 等運算
編譯器/執行環境問題嘗試 std::vector 版本,排除手動管理錯誤

歸併排序完整可運行版(C++ 風格)


#include 
#include 

void Merge(int src[], int dest[], int left, int mid, int right) {
    int i = left, j = mid + 1, k = left;
    while (i <= mid && j <= right) {
        dest[k++] = (src[i] <= src[j]) ? src[i++] : src[j++];
    }
    while (i <= mid) dest[k++] = src[i++];
    while (j <= right) dest[k++] = src[j++];
}

void MergePass(int src[], int dest[], int seg, int n) {
    int i = 0;
    while (i <= n - 2 * seg) {
        Merge(src, dest, i, i + seg - 1, i + 2 * seg - 1);
        i += 2 * seg;
    }
    if (i + seg < n) Merge(src, dest, i, i + seg - 1, n - 1);
    else for (int j = i; j < n; j++) dest[j] = src[j];
}

void MergeSort(int a[], int n) {
    std::vector b(n);
    int s = 1;
    while (s < n) {
        MergePass(a, b.data(), s, n);
        s <<= 1;
        MergePass(b.data(), a, s, n);
        s <<= 1;
    }
}

int main() {
    int a[] = {54, 6, 64, 84, 98, 498, 446, 49, 98, 981};
    int n = sizeof(a) / sizeof(a[0]);
    MergeSort(a, n);
    for (int i = 0; i < n; i++) std::cout << a[i] << ' ';
    std::cout << '\n';
    return 0;
}

核心原則總結

  • 誰配置,誰負責釋放:new[] 必配 delete[],malloc 必配 free
  • RAII 原則:資源獲取即初始化,利用物件生命週期自動管理資源
  • 優先使用標準容器:std::vector/std::string/std::unique_ptr 避免手動記憶體管理
  • CI 整合檢測:編譯加 -fsanitize=address,跑測試自動捕獲洩漏
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved