精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

2025年C++內存泄漏檢測最全指南:從VLD到Valgrind,七款工具深度實戰

開發 前端
內存問題是C++開發中最常見且最棘手的挑戰之一。幸運的是,現代工具鏈提供了豐富的解決方案,從簡單的內置工具到復雜的專業分析器,幾乎涵蓋了所有可能的內存錯誤類型。

Windows 平臺篇:從 Visual Leak Detector (VLD) 開始

Visual Leak Detector:最友好的內存檢測工具

VLD 是一個專為 Windows 平臺 C++ 開發設計的內存泄漏檢測工具,它的優勢在于:

  • 使用簡單,配置方便
  • 支持多種編譯器環境(包括 VC++ 6.0、Visual Studio 等)
  • 自動生成詳細的調用棧信息
  • 對程序性能影響小
  • 完全免費且開源

安裝步驟:

1、下載 VLD 

  • 訪問 GitHub 官方倉庫:https://github.com/KindDragon/vld/releases
  • 下載最新版本的安裝包(例如:vld-2.7.0-setup.exe)

2、安裝 VLD 

  • 運行下載的安裝程序
  • 選擇安裝路徑,完成安裝

3、配置 Visual Studio 項目

  • 右鍵點擊項目 -> 屬性
  • 在"VC++ 目錄"中:

包含目錄:添加 安裝路徑\Visual Leak Detector\include

庫目錄:添加 安裝路徑\Visual Leak Detector\lib\Win64 或 Win32(根據你的項目平臺選擇)

使用方法:

在你的主程序文件頂部添加:

#include <vld.h>

編譯并運行程序,VLD 會自動工作。當程序結束時,它會在輸出窗口顯示詳細的內存泄漏報告。

示例代碼:

#include <vld.h>
#include <iostream>

int main() {
    // 制造一個內存泄漏
    int* leakedMemory = new int[100];
    
    std::cout << "程序運行中..." << std::endl;
    // 注意:這里沒有 delete[] leakedMemory
    
    return 0;
}

調試技巧:

  • VLD 報告會顯示內存泄漏的具體位置(文件名和行號)
  • 顯示完整的調用棧,幫你追蹤泄漏的來源
  • 如果發現大量重復的泄漏,很可能是在循環中忘記釋放內存
  • Debug 模式下使用 VLD 效果最佳

Linux平臺篇

1. mtrace - 小巧精悍的內存追蹤器

mtrace 就像一位盡職的小管家,默默記錄著每一筆"內存賬單"。它是 glibc 的一部分,簡單易用!

使用步驟:

  • 在代碼中布置"監控":
#include <mcheck.h>

int main() {
    mtrace();    // 開啟記賬本
    
    // 你的代碼...
    
    muntrace();  // 合上記賬本
    return 0;
}
  • 運行檢測:
# 設置日志文件
export MALLOC_TRACE=mtrace.log

# 編譯并運行
g++ -g program.cpp -o program
./program

# 查看結果
mtrace ./program mtrace.log

檢測報告示例:

Memory not freed:
-----------------
           Address     Size     Caller
0x000055974621b6a0      0x4  at 0x7f94b084170c
0x000055974621b6c0     0x14  at 0x7f94b084170c

小管家的賬本會告訴你:

  • 哪些內存被分配了但沒有釋放(Address 列)
  • 泄漏了多少內存(Size 列,這里是 4 字節和 20 字節)
  • 調用者的內存地址(Caller 列)- 不過需要額外工具轉換成具體行號

mtrace 的優勢在于輕量級,幾乎不影響程序運行速度。但它的輸出確實比較原始,需要結合 addr2line 等工具來獲取更友好的信息。

對于快速檢查小程序是否存在泄漏,這位小管家已經夠用了!如果需要更詳細的分析,還是建議使用 Valgrind 這樣的重量級工具。

2. Dr. Memory - 跨平臺神器

Dr. Memory 就像一位經驗豐富的醫生,能精確診斷出你的程序哪里"生病"了。它不僅能發現內存泄漏,還能查出其他內存方面的"頑疾"!

安裝步驟:

# 下載安裝包 DrMemory-Linux-2.6.0.tar.gz
訪問網址: https://drmemory.org/page_download.html 
# 解壓并設置
tar -zxvf DrMemory-Linux-2.6.0.tar.gz
echo 'export PATH=$PATH:~/drmemory/DrMemory-Linux-2.5.0/bin' >> ~/.bashrc
source ~/.bashrc

使用方法:

# 編譯時添加調試信息
g++ -g your_program.cpp -o your_program

# 啟動檢測
drmemory -- ./your_program

診斷報告示例:

# 部分輸出:
ERRORS FOUND:
~~Dr.M~~ 0 unique, 0 total unaddressable access(es)      # 未分配內存訪問
~~Dr.M~~ 0 unique, 0 total uninitialized access(es)      # 未初始化內存
~~Dr.M~~ 0 unique, 0 total invalid heap argument(s)      # 無效的堆操作
~~Dr.M~~ 0 unique, 0 total warning(s)                    # 警告信息
~~Dr.M~~ 1 unique, 1 total, 20 byte(s) of leak(s)       # 確認的內存泄漏
~~Dr.M~~ 0 unique, 0 total, 0 byte(s) of possible leak(s) # 可能的內存泄漏

從這份"體檢報告"可以看出:

  • 程序存在一處內存泄漏
  • 泄漏大小為20字節
  • 其他內存使用都很健康

報告還會清晰地顯示:

  • 內存泄漏的位置
  • 泄漏的大小
  • 調用棧信息等

3. Valgrind - 內存檢測界的"老司機"

Valgrind 就像一位經驗豐富的老司機,能帶你穩穩地找出程序中各種隱蔽的內存問題。它不僅能找出內存泄漏,還能檢測數組越界、懸垂指針和各種未定義行為,是 Linux 平臺上最全面的內存檢測工具之一!

安裝與基本使用:

# 安裝
sudo apt-get install valgrind

# 使用 g++ 編譯 C++ 程序
g++ -g -O0 your_program.cpp -o your_program

# 基本使用
valgrind --leak-check=full ./your_program

Valgrind 常用選項:

  • 內存泄漏檢測相關:
--leak-check=full          # 詳細的內存泄漏檢測
--show-leak-kinds=all      # 顯示所有類型的泄漏
--track-origins=yes        # 追蹤未初始化值的來源
--verbose                  # 顯示更詳細的信息
  • 工具選擇:
--tool=memcheck            # 默認工具,檢測內存錯誤
--tool=helgrind            # 檢測線程錯誤,如數據競爭
--tool=cachegrind          # 緩存和分支預測分析
--tool=callgrind           # 函數調用分析
--tool=massif              # 堆內存使用分析

Valgrind 報告解讀:

  • definitely lost:確定的內存泄漏,必須修復
  • indirectly lost:由于指針結構問題導致的泄漏
  • possibly lost:可能的泄漏,取決于你如何管理指針
  • still reachable:程序結束時仍可訪問但未釋放的內存
  • Invalid read/write:讀/寫無效內存地址
  • Source and destination overlap:內存重疊拷貝

實戰場景1:內存泄漏檢測

#include <stdlib.h>

int main() {
    // 分配內存但忘記釋放
    int* array = (int*)malloc(10 * sizeof(int));
    return 0;
}

運行結果:

$ valgrind --leak-check=full ./memory_leak
==15673== Memcheck, a memory error detector
==15673== Command: ./memory_leak
==15673== 
==15673== HEAP SUMMARY:
==15673==     in use at exit: 40 bytes in 1 blocks
==15673==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==15673== 
==15673== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==15673==    at 0x4C31B25: malloc (vg_replace_malloc.c:299)
==15673==    by 0x400544: main (memory_leak.c:5)
==15673== 
==15673== LEAK SUMMARY:
==15673==    definitely lost: 40 bytes in 1 blocks
==15673==    indirectly lost: 0 bytes in 0 blocks
==15673==    possibly lost: 0 bytes in 0 blocks
==15673==    still reachable: 0 bytes in 0 blocks
==15673==    suppressed: 0 bytes in 0 blocks

看這報告多詳細:不僅告訴你泄漏了40字節,還精確指出是在 memory_leak.c 的第5行!

實戰場景2:數組越界訪問

#include <string.h>

int main() {
    char buffer[10];
    // 越界寫入
    strcpy(buffer, "This string is too long for the buffer");
    return 0;
}

運行結果:

xioakang@ubuntu:~/C++/memoryLeak$ valgrind ./test 
==14614== Memcheck, a memory error detector
==14614== Command: ./test
==14614== 
*** stack smashing detected ***: terminated
==14614== 
==14614== Process terminating with default action of signal 6 (SIGABRT)
==14614==    at 0x4B0E00B: raise (raise.c:51)
==14614==    by 0x4AED858: abort (abort.c:79)
==14614==    by 0x4B58265: __libc_message (libc_fatal.c:156)
==14614==    by 0x4BFACD9: __fortify_fail (fortify_fail.c:26)
==14614==    by 0x4BFACA5: __stack_chk_fail (stack_chk_fail.c:24)
==14614==    by 0x109208: main (test.cpp:6)
==14614== 
==14614== HEAP SUMMARY:
==14614==     in use at exit: 0 bytes in 0 blocks
==14614==   total heap usage: 1 allocs, 1 frees, 73,728 bytes allocated
==14614== 
==14614== All heap blocks were freed -- no leaks are possible

老司機立刻就發現了,你在寫入第11個字節時已經越界了!

實戰場景3:使用未初始化的內存

#include <stdio.h>

int main() {
    int a;  // 未初始化
    if (a > 0) {  // 使用未初始化的值
        printf("a is positive\n");
    }
    return 0;
}

運行結果:

xioakang@ubuntu:~/C++/memoryLeak$ valgrind --track-origins=yes ./test 
==14842== Memcheck, a memory error detector
==14842== Command: ./test
==14842== 
==14842== Conditional jump or move depends on uninitialised value(s)
==14842==    at 0x109199: main (test.cpp:8)
==14842==  Uninitialised value was created by a stack allocation
==14842==    at 0x109189: main (test.cpp:6)
==14842== 
==14842== 
==14842== HEAP SUMMARY:
==14842==     in use at exit: 0 bytes in 0 blocks
==14842==   total heap usage: 1 allocs, 1 frees, 73,728 bytes allocated
==14842== 
==14842== All heap blocks were freed -- no leaks are possible

老司機又發現問題了:在第5行,你用一個未初始化的值進行了條件判斷!

實戰場景4:使用已釋放的內存(懸垂指針)

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

int main() {
    int* ptr = (int*)malloc(sizeof(int));
    *ptr = 10;
    free(ptr);        // 釋放內存
    *ptr = 20;        // 使用已釋放的內存
    printf("%d\n", *ptr);
    
    return 0;
}

運行結果:

$ valgrind ./use_after_free
==17982== Memcheck, a memory error detector
==17982== Command: ./use_after_free
==17982== 
==17982== Invalid write of size 4
==17982==    at 0x400563: main (use_after_free.c:8)
==17982==  Address 0x5204040 is 0 bytes inside a block of size 4 free'd
==17982==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17982==    by 0x400558: main (use_after_free.c:7)
==17982== 
==17982== Invalid read of size 4
==17982==    at 0x400572: main (use_after_free.c:9)
==17982==  Address 0x5204040 is 0 bytes inside a block of size 4 free'd
==17982==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17982==    by 0x400558: main (use_after_free.c:7)

Valgrind 立即發現了兩處嚴重錯誤:在釋放內存后,你仍然在第8行寫入數據,第9行讀取數據!這種"懸垂指針"問題是內存漏洞的主要來源!

實戰場景5:重復釋放同一塊內存

#include <iostream>
#include <cstring>

#include <stdlib.h>

int main() {
    int* ptr = (int*)malloc(sizeof(int));

    free(ptr);    // 第一次釋放
    free(ptr);    // 第二次釋放(錯誤)

    return 0;
}

運行結果:

xioakang@ubuntu:~/C++/memoryLeak$ valgrind ./test 
==15063== Memcheck, a memory error detector
==15063== Command: ./test
==15063== 
==15063== Invalid free() / delete / delete[] / realloc()
==15063==    at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==15063==    by 0x1091DA: main (test.cpp:10)
==15063==  Address 0x4e48080 is 0 bytes inside a block of size 4 free'd
==15063==    at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==15063==    by 0x1091CE: main (test.cpp:9)
==15063==  Block was alloc'd at
==15063==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==15063==    by 0x1091BE: main (test.cpp:7)
==15063== 
==15063== 
==15063== HEAP SUMMARY:
==15063==     in use at exit: 0 bytes in 0 blocks
==15063==   total heap usage: 2 allocs, 3 frees, 73,732 bytes allocated
==15063== 
==15063== All heap blocks were freed -- no leaks are possible

Valgrind 立即抓住了第7行的致命錯誤:你正在嘗試第二次釋放同一塊內存!這種"雙重釋放"問題會破壞內存管理器的數據結構,可能引發程序崩潰 。

實戰場景6:錯位的內存釋放(malloc/new 與 free/delete 不匹配)

#include <stdlib.h>
#include <new>

int main() {
    // 使用 new 分配
    int* ptr1 = newint;
    
    // 錯誤:使用 free 釋放
    free(ptr1);
    
    // 使用 malloc 分配
    int* ptr2 = (int*)malloc(sizeof(int));
    
    // 錯誤:使用 delete 釋放
    delete ptr2;
    
    return0;
}

運行結果:

xioakang@ubuntu:~/C++/memoryLeak$ valgrind ./test 
==16032== Memcheck, a memory error detector
==16032== Command: ./test
==16032== 
==16032== Mismatched free() / delete / delete []
==16032==    at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16032==    by 0x10920E: main (test.cpp:12)
==16032==  Address 0x4e48080 is 0 bytes inside a block of size 4 alloc'd
==16032==    at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16032==    by 0x1091FE: main (test.cpp:9)
==16032== 
==16032== Mismatched free() / delete / delete []
==16032==    at 0x483D1CF: operator delete(void*, unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16032==    by 0x109232: main (test.cpp:18)
==16032==  Address 0x4e480d0 is 0 bytes inside a block of size 4 alloc'd
==16032==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16032==    by 0x109218: main (test.cpp:15)

Valgrind 發現了內存釋放方式不匹配的錯誤!記住這個黃金法則:new 配對 delete,malloc 配對 free,混用會導致內存管理器內部結構被破壞!

實戰場景7:多線程數據競爭

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

int shared_counter = 0;

void* increment_counter(void* arg) {
    for (int i = 0; i < 100000; i++) {
        shared_counter++; // 無鎖保護的共享數據訪問
    }
    returnNULL;
}

int main() {
    pthread_t thread1, thread2;
    
    pthread_create(&thread1, NULL, increment_counter, NULL);
    pthread_create(&thread2, NULL, increment_counter, NULL);
    
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    
    printf("Final counter value: %d\n", shared_counter);
    return0;
}

運行結果:

$ g++ -pthread -g thread_race.cpp -o thread_race
$ valgrind --tool=helgrind ./thread_race
==19245== Helgrind, a thread error detector
==19245== Command: ./thread_race
==19245== 
==19245== Possible data race during read of size 4 at 0x601068 by thread #3
==19245==    at 0x400664: increment_counter(void*) (thread_race.cpp:8)
==19245==  This conflicts with a previous write of size 4 by thread #2
==19245==    at 0x400664: increment_counter(void*) (thread_race.cpp:8)
==19245==  Address 0x601068 is 0 bytes inside global var "shared_counter"
==19245==    declared at thread_race.cpp:4

Valgrind 通過 Helgrind 工具精確發現了第8行的多線程數據競爭問題!兩個線程同時修改 shared_counter 變量卻沒有同步機制,導致計數結果不可預測,這是多線程程序中最常見也最難排查的問題類型之一。

4. AddressSanitizer (ASan) - 性能與易用的完美平衡

AddressSanitizer 就像是程序代碼中的防盜報警系統,在問題發生的那一刻就能響起警報!它直接集成在編譯器中,無需額外工具,一條編譯命令就能激活這位24小時值班的守衛。

使用方法:

# 編譯時開啟 ASan(比普通調試只慢2-3倍!)
g++ -fsanitize=address -g your_program.cpp -o your_program

# 直接運行即可
./your_program

常見內存問題及實例:

  • 數組越界訪問:
int main() {
    int array[5] = {0};
    array[10] = 1;  // 越界訪問
    return 0;
}

輸出:

==30498==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd46e3503c at pc 0x5632a6f8b1a9 bp 0x7ffd46e34ff0 sp 0x7ffd46e34fe0
WRITE of size 4 at 0x7ffd46e3503c thread T0
    #0 0x5632a6f8b1a8 in main example.cpp:3
  • 釋放后使用:
int main() {
    int* p = new int(42);
    delete p;
    *p = 10;  // 使用已釋放的內存
    return 0;
}

輸出:

==30655==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000000040 at pc 0x7fb5617bb1a9 bp 0x7ffc28c56f10 sp 0x7ffc28c56f00
WRITE of size 4 at 0x606000000040 thread T0
    #0 0x7fb5617bb1a8 in main example.cpp:4
  • 內存泄漏:
int main() {
    int* p = new int[100];  // 沒有配對的 delete[]
    return 0;
}

輸出:

==31041==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 400 bytes in 1 objects allocated from:
    #0 0x7f84e5bd4bc8 in operator new[](unsigned long) 
    #1 0x55907893a1b9 in main example.cpp:2
  • 棧緩沖區溢出:
void function() {
    char buffer[10];
    strcpy(buffer, "This string is too long for the buffer");
}

輸出:

==31299==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffce822c8aa at pc 0x7f9e5f43282c
WRITE of size 38 at 0x7ffce822c8aa thread T0
    #0 0x7f9e5f43282b in strcpy
    #1 0x561fe803a1c9 in function example.cpp:3

AddressSanitizer 是開發階段最高效的內存檢測工具之一。它直接集成到編譯過程中,運行速度快(只比普通調試慢2-3倍),同時能捕獲絕大多數內存問題。無需額外安裝,一鍵開啟,是現代 C/C++ 開發的必備神器!

5. Memory Sanitizer (MSan) - 未初始化內存檢測專家

Memory Sanitizer 就像是一位專注于特定領域的安全專家,它的獨門絕技是:發現并報告程序中使用未初始化內存的問題。這類問題特別隱蔽,往往會導致程序行為不可預測,MSan 正是為此而生!

使用方法:

# g++ 可能不支持 MSan,但是 clang 支持
# 安裝 Clang
sudo apt-get install clang

# 編譯時開啟 MSan 
clang -fsanitize=memory -fPIE -pie -g your_program.cpp -o your_program

參數說明:

  • -fsanitize=memory: 啟用 Memory Sanitizer
  • -fPIE 和 -pie: 生成位置無關的可執行文件(MSan 需要)
  • -g: 添加調試信息,使報告顯示源碼行號

典型問題示例:

  • 未初始化的局部變量:
int main() {
    int value;  // 未初始化
    int result = value + 10;  // 使用未初始化的值
    return result;
}

輸出:

==31604==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x7f3a53be02cf in main uninit_var.cpp:3:18
    #1 0x7f3a53814023 in __libc_start_main (...) 
    #2 0x7f3a53be014e in _start (...)
SUMMARY: MemorySanitizer: use-of-uninitialized-value uninit_var.cpp:3:18 in main
  • 結構體部分初始化:
struct Point {
    int x;
    int y;
};

int main() {
    Point p;
    p.x = 5;  // 只初始化了x
    // p.y 未初始化
    
    int sum = p.x + p.y;  // 使用未初始化的p.y
    
    // 添加條件判斷,使未初始化值的使用更明顯
    if (sum > 10) {
        return1;
    }
    
    return0;
}

輸出:

==31842==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x7f52f8abd32f in main struct_partial_init.cpp:9:20
    #1 0x7f52f87cb023 in __libc_start_main (...)
    #2 0x7f52f8abd14e in _start (...)
SUMMARY: MemorySanitizer: use-of-uninitialized-value struct_partial_init.cpp:9:20 in main
  • 通過指針傳播未初始化值:
void copy(int* dst, int* src) {
    *dst = *src;  // 傳播可能未初始化的值
}

int main() {
    int a;  // 未初始化
    int b;
    
    copy(&b, &a);  // 將未初始化的a復制到b
    return b;  // 使用可能未初始化的值
}

輸出:

==32067==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x7fef55aa834e in copy pointer_propagation.cpp:2:13
    #1 0x7fef55aa83a1 in main pointer_propagation.cpp:8:5
    #2 0x7fef557b6023 in __libc_start_main (...)
SUMMARY: MemorySanitizer: use-of-uninitialized-value pointer_propagation.cpp:2:13 in copy
  • 條件分支中的未初始化:
int main(int argc, char* argv[]) {
    int value;
    
    if (argc > 1) {
        value = 10;  // 只在條件為真時初始化
    }
    
    return value;  // 如果argc <= 1,value未初始化
}

輸出:

==32301==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x7f9df5c7c3f6 in main conditional_init.cpp:8:12
    #1 0x7f9df5a8a023 in __libc_start_main (...)
SUMMARY: MemorySanitizer: use-of-uninitialized-value conditional_init.cpp:8:12 in main

MSan 的特點:

  • 專注于單一任務:只檢測未初始化內存使用
  • 誤報率低:幾乎沒有假陽性結果
  • 詳細的調用棧信息:準確定位問題源頭
  • 檢測復雜傳播:跟蹤未初始化值如何在程序中流動

使用注意事項:

MSan 需要所有代碼都開啟檢測:

# 編譯你的庫時也要加上這些選項
g++ -fsanitize=memory -fPIE -pie -g your_library.cpp -c
  • 與 ASan 不能同時使用(需分開編譯檢測)
  • 主要用于 Linux/Clang 環境,GCC 支持有限

Memory Sanitizer 是查找那些"幽靈般"問題的利器 — 當你的程序行為不一致,且其他工具找不出原因時,MSan 很可能是你需要的救星!

6. heaptrack - 現代化的內存分析器

heaptrack 就像一位精明的財務顧問,不僅告訴你"錢哪里漏了",還能詳細分析"錢怎么花的"!它是一個全方位的內存分析工具,能夠追蹤所有內存分配、釋放情況,并生成直觀的可視化報告,讓你一眼看清內存使用的全貌。

安裝與使用:

# 安裝
sudo apt-get install heaptrack heaptrack-gui
# 編譯程序
g++ -g your_program.cpp -o your_program

# 基本使用
heaptrack ./your_program
# 或者附加到正在運行的程序
heaptrack -p $(pidof your_program)

# 分析結果
heaptrack_gui heaptrack.your_program.12345.gz

實戰場景1:內存泄漏檢測

#include <stdlib.h>
#include <unistd.h>

void leak_memory() {
    void* ptr = malloc(1024);
    // 忘記釋放
}

int main() {
    for (int i = 0; i < 100; i++) {
        leak_memory();
        usleep(10000);  // 短暫暫停,便于觀察
    }
    return0;
}

運行結果:

$ heaptrack ./memory_leak
heaptrack output will be written to "heaptrack.memory_leak.12345.gz"
starting application...
...
$ heaptrack_gui heaptrack.memory_leak.12345.gz

heaptrack_gui 會打開一個圖形界面,顯示:

  • 精確的內存泄漏位置和數量
  • 隨時間變化的內存使用圖表
  • 內存分配調用棧和熱點函數
  • 內存分配大小分布

你能清晰地看到 leak_memory() 函數在不斷分配內存但從不釋放,總內存使用量呈階梯狀上升!

實戰場景2:內存分配熱點分析

#include <stdlib.h>
#include <string.h>

void allocate_small() {
    for (int i = 0; i < 1000; i++) {
        char* buffer = (char*)malloc(64);
        memset(buffer, 0, 64);
        free(buffer);
    }
}

void allocate_large() {
    for (int i = 0; i < 10; i++) {
        char* buffer = (char*)malloc(1024 * 1024);
        memset(buffer, 0, 1024 * 1024);
        free(buffer);
    }
}

int main() {
    allocate_small();
    allocate_large();
    return0;
}

運行結果:

$ heaptrack ./allocation_hotspots
heaptrack output will be written to "heaptrack.allocation_hotspots.12345.gz"
...
$ heaptrack_gui heaptrack.allocation_hotspots.12345.gz

heaptrack_gui 會顯示:

  • allocate_small() 函數有最多的分配次數
  • allocate_large() 函數有最大的內存吞吐量
  • 完整調用棧和每個函數的分配情況
  • 分配的具體大小分布圖表

實戰場景3:附加到運行中的進程

假設我們有一個長時間運行的服務器程序,它在運行一段時間后內存使用量異常增長:

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

void slowly_leak() {
    staticint iteration = 0;
    iteration++;
    
    // 每10次迭代泄漏一些內存
    if (iteration % 10 == 0) {
        void* leak = malloc(1024 * 100);  // 泄漏約100KB
        printf("Iteration %d: Potential leak at %p\n", iteration, leak);
    }
    
    // 正常分配和釋放的內存
    void* normal = malloc(2048);
    free(normal);
    
    sleep(1);  // 每秒執行一次
}

int main() {
    printf("Server started with PID: %d\n", getpid());
    printf("Waiting for connections...\n");
    
    // 模擬服務器主循環
    while (1) {
        slowly_leak();
    }
    
    return0;
}

運行與分析步驟:

  • 編譯并啟動服務器程序:
$ g++ -g server.c -o server
$ ./server
Server started with PID: 23456
Waiting for connections...
Iteration 10: Potential leak at 0x55f7a83e12a0
Iteration 20: Potential leak at 0x55f7a83e1940
...
  • 在另一個終端窗口,附加 heaptrack 到運行中的進程:
$ heaptrack -p 23456
heaptrack output will be written to "heaptrack.server.23456.12345.gz"
injecting into application via GDB, this might take some time...
injection finished
  • 讓服務器繼續運行一段時間,然后在 heaptrack 終端按 Ctrl+C 結束追蹤
  • 分析結果:
$ heaptrack_gui heaptrack.server.23456.12345.gz

heaptrack 的獨特優勢:

  • 實時分析:可以在程序運行時實時查看內存使用情況
heaptrack -o output_file ./your_program &
heaptrack_gui output_file
  • 最小化程序干擾:比 Valgrind 更輕量,對程序執行速度影響小
# heaptrack的性能開銷通常為20-50%
# valgrind的性能開銷通常為3-10倍
  • 直觀可視化:提供交互式圖形界面
# 支持多種視圖
# - 時間線視圖:查看內存使用隨時間變化
# - 火焰圖:查看內存分配調用棧
# - 熱點函數:查看內存分配最頻繁的函數
  • 命令行分析選項:
# 不使用GUI也可以查看結果
heaptrack_print heaptrack.your_program.12345.gz

heaptrack 是內存分析工具中的新秀,它結合了詳細的分析能力和現代化的界面,特別適合需要深入了解程序內存使用模式的開發者。它不只告訴你"有沒有泄漏",還能告訴你"內存都用在哪了",幫助你優化程序的整體內存使用效率!

7. gperftools - Google出品的高性能工具集

gperftools 就像一套專業的程序性能診療設備,由 Google 開發,包含了內存分析、CPU 分析和堆檢查等多種工具。它以高效、低開銷著稱,是 Google 內部大規模系統性能優化的秘密武器,尤其是其中的 TCMalloc 內存分配器,比標準庫的 malloc 性能更強!

安裝與使用:

# 安裝
sudo apt-get install google-perftools libgoogle-perftools-dev

# 編譯程序
g++ -g your_program.cpp -o your_program

# 基本使用(內存泄漏檢測)
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc.so HEAPCHECK=normal ./your_program

# CPU 性能分析
LD_PRELOAD=/usr/lib/libprofiler.so CPUPROFILE=cpu.prof ./your_program
google-pprof --text ./your_program cpu.prof

實戰場景1:內存泄漏檢測

#include <stdlib.h>

void leaky_function() {
    int* data = new int[100];  // 分配但不釋放
}

int main() {
    for (int i = 0; i < 10; i++) {
        leaky_function();
    }
    return 0;
}

運行結果:

$ g++ -g memory_leak.cpp -o memory_leak 
$ LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc.so HEAPCHECK=normal ./memory_leak

WARNING: Perftools heap leak checker is active -- Performance may suffer
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 4000 bytes in 10 objects
The 1 largest leaks:
Using local file ./memory_leak.
/usr/bin/addr2line: DWARF error: section .debug_info is larger than its filesize! (0x93f189 vs 0x530e70)
Leak of 4000 bytes in 10 objects allocated from:
 @ 55881f71719f leaky_function
 @ 55881f7171c4 main
 @ 7f99004e5083 __libc_start_main
 @ 55881f7170ce _start


... [more similar leaks] ...

If this is a false positive, try running with HEAP_CHECK_DRACONIAN.

gperftools 的堆檢查器清晰地標識出了泄漏位置和大小,按照大小排序展示最嚴重的泄漏!

實戰場景2:高性能內存分配器 TCMalloc

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <vector>
#include <thread>

void memory_task(int thread_id) {
    std::vector<void*> pointers;
    
    for (int i = 0; i < 1000000; i++) {
        size_t size = 8 + (i % 64) * 16;
        void* ptr = malloc(size);
        pointers.push_back(ptr);
        
        if (i % 7 == 0 && !pointers.empty()) {
            size_t index = i % pointers.size();
            free(pointers[index]);
            pointers[index] = NULL;
        }
    }
    
    // 清理
    for (void* ptr : pointers) {
        if (ptr) free(ptr);
    }
}

int main() {
    clock_t start = clock();
    
    // 創建8個線程,同時進行內存密集操作
    std::thread threads[8];
    for (int i = 0; i < 8; i++) {
        threads[i] = std::thread(memory_task, i);
    }
    
    // 等待所有線程完成
    for (int i = 0; i < 8; i++) {
        threads[i].join();
    }
    
    clock_t end = clock();
    printf("Execution time: %f seconds\n", (double)(end - start) / CLOCKS_PER_SEC);
    
    return0;
}

運行結果對比:

# 使用標準庫 malloc
$ g++ -g malloc_benchmark.cpp -o std_malloc
$ ./std_malloc
Execution time: 35.994701 seconds

# 使用 TCMalloc
$ g++ -g malloc_benchmark.cpp -o tcmalloc_version -ltcmalloc
$ ./tcmalloc_version
Execution time: 8.005729 seconds

TCMalloc 在這種多線程頻繁分配/釋放場景下,性能提升好幾倍!

實戰場景3:CPU 性能分析

#include <math.h>
#include <stdio.h>
#include <unistd.h>

void cpu_intensive_function1() {
    double result = 0;
    for (int i = 0; i < 1000000; i++) {
        result += sin(i) * cos(i);
    }
}

void cpu_intensive_function2() {
    double result = 0;
    for (int i = 0; i < 2000000; i++) {
        result += sqrt(i) * log(i+1);
    }
}

void mixed_function() {
    cpu_intensive_function1();
    sleep(1);  // IO等待
    cpu_intensive_function2();
}

int main() {
    mixed_function();
    return0;
}

運行與分析:

$ g++ -g cpu_profile.cpp -o cpu_profile
$ LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libprofiler.so CPUPROFILE=cpu.prof CPUPROFILE_FREQUENCY=1000 ./cpu_profile
$ google-pprof --text ./cpu_profile cpu.prof
Using local file cpu.prof.
/usr/bin/addr2line: DWARF error: section .debug_info is larger than its filesize! (0x17356f vs 0x13c5f8)
/usr/bin/addr2line: DWARF error: section .debug_info is larger than its filesize! (0x93f189 vs 0x530e70)
Total: 6 samples
       4  66.7%  66.7%        4  66.7% f64xsubf128
       1  16.7%  83.3%        3  50.0% cpu_intensive_function2
       1  16.7% 100.0%        1  16.7% logf64
       0   0.0% 100.0%        6 100.0% __libc_start_main
       0   0.0% 100.0%        6 100.0% _start
       0   0.0% 100.0%        3  50.0% cpu_intensive_function1
       0   0.0% 100.0%        6 100.0% main
       0   0.0% 100.0%        6 100.0% mixed_function
       0   0.0% 100.0%        1  16.7% std::cos
       0   0.0% 100.0%        2  33.3% std::log
       0   0.0% 100.0%        2  33.3% std::sin
$ google-pprof --web ./test cpu.prof

生成一個可視化的調用圖,清晰顯示每個函數消耗的 CPU 時間比例,幫你精確定位性能瓶頸!

gperftools 的獨特優勢:

  • TCMalloc - 高性能內存分配器:
# 簡單使用
g++ your_program.cpp -o your_program -ltcmalloc

# 查看內存使用統計
$ MALLOCSTATS=1 ./your_program
  • 低開銷的分析工具:
# 比 Valgrind 等工具的性能影響小得多
# 適合生產環境使用
  • 靈活的內存泄漏檢測級別:
# 不同級別的檢查
HEAPCHECK=minimal   # 最快,僅檢查明顯泄漏
HEAPCHECK=normal    # 平衡性能和檢測能力
HEAPCHECK=strict    # 更嚴格的檢查
HEAPCHECK=draconian # 最嚴格的檢查
  • 可與其他工具整合:
# 配合 pprof 可視化工具使用
google-pprof --web ./your_program cpu.prof  # 在瀏覽器中查看

gperftools 是一套強大而全面的性能工具集,特別適合對性能有嚴格要求的大型項目。它不僅能幫你找出內存問題,還能幫你優化程序的整體性能,是資深開發者的必備工具!

?? 實用建議

選擇合適的工具:

  • 剛入門? 從簡單的工具開始(Windows上的VLD,Linux上的mtrace)
  • 大型項目? 選擇全面的分析工具(Valgrind或Dr. Memory)
  • 對性能敏感? 使用編譯器集成工具(AddressSanitizer)
  • 需要分析內存使用模式? 嘗試heaptrack或gperftools

各工具性能對比:

  • mtrace:性能開銷極小(<5%),幾乎不影響程序運行速度,但功能局限于基本內存泄漏檢測
  • Valgrind:性能開銷最大,使程序運行速度降低10-30倍,但提供最全面的內存錯誤檢測(泄漏、越界、未初始化等)
  • Dr. Memory:中高性能開銷,使程序運行速度降低5-10倍,檢測能力接近Valgrind但更輕量
  • AddressSanitizer:中等性能開銷,使程序運行速度降低2-3倍,檢測效率高,適合開發階段日常使用
  • Memory Sanitizer:與AddressSanitizer類似,使程序運行速度降低2-3倍,專注于未初始化內存檢測
  • heaptrack:中等性能開銷,使程序運行速度降低1.5-3倍,提供詳細的內存分配分析和可視化
  • gperftools:低性能開銷,使程序運行速度降低1.2-2倍,提供良好的內存分析能力,適合性能敏感環境

檢測策略建議:

  • 開發階段:使用輕量級工具(AddressSanitizer/VLD)進行頻繁檢測
  • 集成測試:使用全面工具(Valgrind/Dr. Memory)進行深入檢測
  • 生產環境:使用低開銷工具(gperftools)或采樣分析

防患于未然的代碼實踐:

  • 使用智能指針(std::unique_ptr, std::shared_ptr)
  • 采用RAII原則(資源獲取即初始化)
  • 盡量避免裸指針和手動內存管理
  • 使用標準容器而非原始數組

針對性檢測:

  • 內存泄漏:Valgrind, VLD, Dr. Memory
  • 緩沖區溢出:AddressSanitizer
  • 未初始化內存:Memory Sanitizer, Valgrind
  • 性能瓶頸分析:gperftools, heaptrack

總結

內存問題是C++開發中最常見且最棘手的挑戰之一。幸運的是,現代工具鏈提供了豐富的解決方案,從簡單的內置工具到復雜的專業分析器,幾乎涵蓋了所有可能的內存錯誤類型。

對于初學者,建議從簡單的工具開始,如 Windows 上的 VLD 或 Linux 上的 mtrace,這些工具容易上手且能滿足基本需求。隨著經驗的積累,可以逐漸嘗試更專業的工具如 Valgrind 或 AddressSanitizer,它們能提供更全面的分析和更準確的診斷。

關鍵是要將內存檢測作為開發流程的一部分,而不是事后補救的措施。良好的編碼習慣、合適的工具選擇以及持續的檢測,是防止內存問題的最佳組合。

記住,最好的修復是預防 —— 通過使用現代 C++ 特性如智能指針、RAII 和標準容器,可以從根本上減少內存管理錯誤的可能性。讓我們擁抱這些工具和技術,寫出更健壯、更可靠的C++代碼!

責任編輯:武曉燕 來源: 跟著小康學編程
相關推薦

2015-04-17 10:35:51

c++c++程序內存泄漏檢測代碼

2011-06-16 09:28:02

C++內存泄漏

2024-07-03 11:28:15

2013-08-02 09:52:14

AndroidApp內存泄漏

2025-10-31 07:32:00

內存泄漏C++編程

2011-08-15 10:16:55

內存泄露

2025-03-25 09:00:00

2021-03-26 05:59:10

內存檢測工具

2015-06-25 11:21:33

C++Objective-C

2022-07-30 23:45:09

內存泄漏檢測工具工具

2024-04-19 08:00:00

2025-11-17 09:27:09

2025-05-13 00:48:41

2017-09-07 16:52:23

2024-01-22 11:33:17

C++編程語言開發

2025-07-30 07:57:23

2025-02-11 12:37:30

2025-02-18 00:16:30

2025-02-26 08:50:00

2025-09-26 02:00:55

JDKCPU內存
點贊
收藏

51CTO技術棧公眾號

久久国产精品美女| 成人日韩欧美| 麻豆精品新av中文字幕| 毛片精品免费在线观看| 青青草视频网站| abab456成人免费网址| 亚洲男同性视频| 欧美日韩电影一区二区| 99精品久久久久久中文字幕| 亚洲欧美视频一区二区三区| 久久精品一区中文字幕| 少妇大叫太粗太大爽一区二区| 国内自拍亚洲| 精品久久久久久久久久久久| 在线观看欧美激情| 激情综合闲人网| 成人小视频免费在线观看| 国产欧美日韩亚洲精品| 在线观看日韩中文字幕| 欧美/亚洲一区| 这里只有精品在线观看| 亚洲の无码国产の无码步美| 久久久91麻豆精品国产一区| 欧美性猛交xxxx乱大交退制版| 黄色一级视频在线播放| 国内精品久久久久久野外| 久久久久久久久久久久久女国产乱| 亚洲综合最新在线| 这里只有精品9| 视频一区免费在线观看| 2025国产精品视频| 久一区二区三区| 综合一区在线| 久久中文字幕国产| 亚洲综合第一区| 精品产国自在拍| 国产一区二区三区在线| 短视频在线观看| 日韩av字幕| 亚洲精品国产精品国产自| 亚洲麻豆一区二区三区| 亚洲超碰在线观看| 日韩午夜在线播放| 伊人成人免费视频| 涩涩涩久久久成人精品| 欧美日韩一区二区三区在线看| 欧美 日韩 国产一区| 最新中文字幕在线播放| 欧美日韩一区二区在线播放| 国产 日韩 亚洲 欧美| xxxx另类黑人| 亚洲不卡av一区二区三区| 女人帮男人橹视频播放| 日本在线视频www鲁啊鲁| 亚洲精品日日夜夜| 精品无码国产一区二区三区av| 春色校园综合激情亚洲| 精品国产精品自拍| 日本成人在线免费视频| 日本另类视频| 宅男噜噜噜66一区二区66| www.亚洲自拍| 国产丝袜一区| 亚洲欧美日韩第一区| 337人体粉嫩噜噜噜| 日韩欧美一区二区三区免费看| 日韩中文字幕在线观看| 国产午夜手机精彩视频| 激情偷拍久久| 日韩av大片在线| 亚洲天堂视频网| 国产乱码精品一区二区三区五月婷| y111111国产精品久久婷婷| 日本黄色不卡视频| 国产欧美一区二区精品忘忧草| 亚洲国产精品一区二区第四页av| 2024最新电影在线免费观看| 亚洲丶国产丶欧美一区二区三区| 欧美日韩国产精品激情在线播放| 久久av影院| 欧美v日韩v国产v| 国产熟妇搡bbbb搡bbbb| 91精品精品| 66m—66摸成人免费视频| 日批视频免费观看| 高清av一区二区| 欧美精品一区在线发布| 黄色网址视频在线观看| 五月婷婷激情综合| 成人综合久久网| 乱中年女人伦av一区二区| 在线视频精品一| 国产在线观看99| 日本aⅴ免费视频一区二区三区 | 国产精品久久乐| 日韩一级在线观看| 欧美多人猛交狂配| 国产精品第十页| 国产精品久久久久久网站 | 亚洲精选在线观看| 精品国产精品国产精品| 美女精品一区| 成人免费在线一区二区三区| jizz亚洲| 欧美日韩免费看| 在线观看视频在线观看| jiujiure精品视频播放| 国内精品400部情侣激情| 最近日韩免费视频| 91免费精品国自产拍在线不卡| 中文字幕在线中文字幕日亚韩一区| 国产在线88av| 欧美不卡在线视频| 激情高潮到大叫狂喷水| 国产亚洲亚洲| 国产传媒一区| 国产精品久久麻豆| 欧美亚洲愉拍一区二区| 美女又爽又黄视频毛茸茸| 欧美一区二区三区免费看| 国产精品视频大全| 黄色在线小视频| 天天操天天干天天综合网| 最好看的中文字幕| 亚洲成人精品| 国产又爽又黄的激情精品视频| 国产在线网站| 色婷婷综合久久久久中文| 亚洲成va人在线观看| 一区二区三区国产福利| 成人影院入口| 亚洲精选在线观看| 中日韩黄色大片| a亚洲天堂av| 免费一级淫片aaa片毛片a级| 国产福利91精品一区二区| 国产一区二区美女视频| 无码人妻精品一区二| 久久久久综合网| 2022亚洲天堂| 免费电影一区二区三区| 欧美又大又硬又粗bbbbb| 少妇高潮一区二区三区99小说| 亚洲黄色尤物视频| 亚洲日本久久久| 激情自拍一区| 久久综合一区二区三区| 在线观看涩涩| 亚洲人精品午夜在线观看| 伦av综合一区| 国产欧美久久久精品影院| 香蕉视频禁止18| 91综合久久| 91香蕉国产在线观看| 在线欧美三级| 欧美精品一区二区三区高清aⅴ| 日本亚洲欧美在线| 久久久久9999亚洲精品| 免费看污黄网站| 欧美oldwomenvideos| 91情侣偷在线精品国产| 丁香花在线电影小说观看| 亚洲高清福利视频| 久久久久久无码午夜精品直播| 欧美国产日本韩| 日韩av片免费观看| 亚洲无吗在线| 欧美一区二区影视| 四虎精品永久免费| 欧美精品videosex极品1| 天天操天天插天天射| 色丁香久综合在线久综合在线观看| 日本美女bbw| 国产在线精品一区二区| 国产精品裸体瑜伽视频| 精品久久电影| 91九色在线观看| 免费成人直播| 久久在线免费视频| 天堂成人在线视频| 欧美日韩不卡在线| 国产无套内射又大又猛又粗又爽| 久久久久国产一区二区三区四区 | 亚洲欧美三级在线| 一区二区三区亚洲视频| 亚洲国产精品麻豆| 性少妇xx生活| 99久久精品免费看国产 | 国产成人精品影视| 欧美一级片中文字幕| 一区二区三区四区日韩| 九9re精品视频在线观看re6 | 懂色一区二区三区av片| 日韩av福利| 色综合男人天堂| 国产特黄在线| 亚洲国产成人精品电影| 91精品国产乱码久久久久| 欧美性xxxxxxxxx| 日本aⅴ在线观看| 久久精品一级爱片| 中国免费黄色片| 国内久久婷婷综合| 91色国产在线| 日韩视频中文| 蜜桃视频一区二区在线观看| 欧美日韩老妇| 久久久久久久久久久久久9999| 97色婷婷成人综合在线观看| 欧洲精品在线视频| 乱插在线www| 久久精品国产成人| 青青青免费视频在线2| 欧美大胆人体bbbb| 国产区精品在线| 欧美日韩在线不卡| www.久久久久久久| 天天综合天天综合色| 九九九久久久久| 综合欧美亚洲日本| 国产又黄又粗的视频| 久久日韩粉嫩一区二区三区| 香蕉久久久久久av成人| 狠狠色丁香久久婷婷综合丁香| 国产视频一区二区三区在线播放 | av亚洲免费| 欧美精品免费观看二区| gogo人体一区| y111111国产精品久久婷婷| 粉嫩一区二区三区在线观看| 国产精品日韩在线| 韩国成人在线| 国产精品99导航| 超碰一区二区| 国产激情久久久| 自拍在线观看| 国产精品爱久久久久久久| xx欧美视频| 日韩**中文字幕毛片| 免费亚洲电影| 国产精品高清网站| 91国内外精品自在线播放| 国产精品国语对白| 草莓视频成人appios| 国产日韩换脸av一区在线观看| 福利一区二区免费视频| 国产www精品| 蜜桃视频在线网站| 欧洲亚洲妇女av| 成人做爰视频www网站小优视频| 日韩女优在线播放| 日本美女久久| 成人综合国产精品| julia中文字幕一区二区99在线| 国产三区精品| 国产乱码精品一区二区三区四区| 日本婷婷久久久久久久久一区二区| 国产91精品对白在线播放| 日本不卡一区二区三区视频| 成人综合专区| 亚洲av综合色区| 一区免费在线| 男女曰b免费视频| 美女脱光内衣内裤视频久久影院| 国产欧美一区二| 成人亚洲一区二区一| 亚洲熟妇一区二区三区| 中国av一区二区三区| 国产探花在线播放| 欧美日韩另类字幕中文| 中文字幕在线视频免费| 日韩一区二区三区视频在线观看| 欧美一区二区公司| 亚洲少妇激情视频| caoporm免费视频在线| 4k岛国日韩精品**专区| 国产欧美自拍| 国产精品区一区二区三在线播放| 亚洲妇女av| 欧美日韩一级在线| 国产精品一国产精品k频道56| 国产又大又黄又粗的视频| 国产99精品在线观看| 日韩精品无码一区二区三区久久久| 亚洲天天做日日做天天谢日日欢 | 久久综合久久综合这里只有精品| 日韩在线观看| 日本中文字幕亚洲| 理论片日本一区| 97精品人妻一区二区三区蜜桃| 国产日韩欧美a| 欧美国产在线看| 欧美伊人精品成人久久综合97| 亚洲va欧美va| 最近2019好看的中文字幕免费| 久久男人av资源站| 成人免费在线网址| 欧美丝袜激情| www.av中文字幕| 国产高清视频一区| 国产又粗又硬视频| 福利视频第一区| 成人黄色免费视频| 日韩在线观看网址| 国产免费不卡| 成人动漫视频在线观看免费| 欧美岛国激情| 日本一本二本在线观看| 大白屁股一区二区视频| 二区三区四区视频| 色狠狠av一区二区三区| 香蕉视频黄在线观看| 欧美黑人国产人伦爽爽爽| 色综合久久久| 亚洲一区二三| 日本免费新一区视频 | 亚洲视频在线观看三级| 看黄色一级大片| 亚洲欧洲第一视频| 免费在线小视频| 国产精品免费观看高清| 欧美成熟视频| 国产高清999| 中文字幕在线一区二区三区| 无码视频一区二区三区| 亚洲欧美日韩国产成人| 天堂中文在线播放| 精品高清视频| 亚洲麻豆一区| 少妇精品无码一区二区三区| 一区二区三区在线视频观看58 | 国产又黄又爽免费视频| 久久精品国产免费| www.4hu95.com四虎| 欧美综合欧美视频| www亚洲人| 国产精品私拍pans大尺度在线| 欧美精品一区二区三区精品| 999精品网站| 欧美韩国日本不卡| 伊人网站在线观看| 日韩在线中文字| 99tv成人影院| 国产制服91一区二区三区制服| 国产一区二区按摩在线观看| 卡通动漫亚洲综合| 日韩限制级电影在线观看| 高清电影在线免费观看| 国产日韩欧美二区| 久久99伊人| 日韩不卡av在线| 免费观看成人毛片| 亚洲一二在线观看| 欧美特黄色片| 懂色av一区二区三区四区五区| 国产精品羞羞答答xxdd| 日韩精品久久久久久久| 亚洲欧美日韩国产中文| 日本久久久久| 乱子伦一区二区| 国产成人在线视频网站| 日本在线视频免费| 国产一区二区激情| 欧美午夜在线播放| 久在线观看视频| 日本一区二区三区四区在线视频| 一级爱爱免费视频| 色综合视频网站| 蜜臀久久99精品久久一区二区| 日本三级黄色网址| 亚洲一区二区三区视频在线| 色哟哟在线观看| 91精品久久久久久综合乱菊| 国产精品v亚洲精品v日韩精品| 日本少妇色视频| 在线不卡免费欧美| 国产高潮在线| 亚洲国产一区二区精品视频| 国产精品自拍av| 无码一区二区三区| 色与欲影视天天看综合网| 一本色道久久综合亚洲精品酒店 | 美女视频亚洲色图| 亚洲xxxx2d动漫1| 亚洲一级二级在线| 福利视频在线看| 国产精品自拍首页| 蜜臀久久99精品久久久久久9| 久久久久久久福利| 中文字幕精品在线| 乱中年女人伦av一区二区| 看看黄色一级片| 一本在线高清不卡dvd| 色屁屁www国产馆在线观看| 欧美午夜欧美| 不卡在线视频中文字幕| 91影院在线播放| 国产成人一区二| 怡红院精品视频在线观看极品| 国产又粗又猛又爽又黄的视频四季 |