首页 服务器系统 Linux

Valgrind 一款 Linux 环境下的内存调试和性能分析工具

Valgrind是一种用于检测和调试内存错误的开源工具集。它提供了一套强大的工具,可以帮助开发人员发现和修复内存泄漏、使用未初始化的内存、访问已释放的内存等常见的内存错误。

Valgrind的主要特点和功能包括:

1. 内存错误检测(Memcheck):Valgrind能够检测到内存泄漏、使用未初始化的内存、访问已释放的内存等内存错误。它会在运行程序时对内存进行跟踪,并在发现错误时给出警告和详细的错误信息。

2. 性能分析(Callgrind):Valgrind可以对程序进行性能分析,帮助开发人员找到程序中的性能瓶颈和优化机会。它可以提供函数级别的调用图、内存分配和释放的统计信息等。

3. 线程调试(Helgrind):Valgrind支持多线程程序的调试,可以检测到线程间的竞争条件和死锁等问题。它能够跟踪线程的创建、销毁和同步操作,并提供相关的调试信息。

4. 缓存分析(Cachegrind):Valgrind可以了解程序中的缓存访问模式,找到可能存在的缓存效率问题,并进行相应的优化

使用Valgrind可以帮助开发人员提高代码质量和性能,减少内存错误和性能问题的出现。它适用于C、C++等语言的应用程序,并且在Linux和其他类Unix系统上广泛使用。

Valgrind 工具集

// check_memory.cpp

// 编译程序
// g++ check_memory.cpp -o check_memory -g

//运行程序
// valgrind --leak-check=full --track-origins=yes -s ./check_memory

// 程序输出
// ==25448== Memcheck, a memory error detector
// ==25448== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
// ==25448== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
// ==25448== Command: ./check_memory
// .....
// ==25448== LEAK SUMMARY:
// ==25448==    definitely lost: 8 bytes in 2 blocks
// ==25448==    indirectly lost: 0 bytes in 0 blocks
// ==25448==      possibly lost: 0 bytes in 0 blocks
// ==25448==    still reachable: 0 bytes in 0 blocks
// ==25448==         suppressed: 0 bytes in 0 blocks
// ==25448== 
// ==25448== ERROR SUMMARY: 8 errors from 8 contexts (suppressed: 0 from 0)

#include <iostream>

int main()
{
    int *ptr = new int(5);
    int a;

    // 内存越界读
    std::cout << ptr[6] << std::endl;

    // 内存越界写
    ptr[6] = 1;

    // 使用已经释放的内存
    std::cout << *ptr << std::endl;

    // 使用未初始化的变量
    std::cout << a << std::endl;

    // 内存泄漏
    ptr = new int(5);

    return 0;
}
// perf_profile.cpp

// 编译程序
// g++ perf_profile.cpp -o perf_profile -g

// 运行程序
//  valgrind --tool=callgrind ./perf_profile
//  valgrind callgrind_annotate callgrind.out.*

// 程序输出
// ......
// --------------------------------------------------------------------------------
// Ir
// --------------------------------------------------------------------------------
// 175,705,384 (100.0%)  PROGRAM TOTALS
// --------------------------------------------------------------------------------
// Ir                   file:function
// --------------------------------------------------------------------------------
// ....

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> numbers;
    for (int i = 0; i < 1000000; i++)
    {
        numbers.push_back(i);
    }

    int sum = 0;
    for (int num : numbers)
    {
        sum += num;
    }

    std::cout << "Sum: " << sum << std::endl;

    return 0;
}
// thread_debug.cpp

// 编译程序
// g++ thread_debug.cpp -o thread_debug -g

// 运行程序
// valgrind -tool=helgrind --history-level=approx -s ./thread_debug

// 程序输出
// ==35418== ----------------------------------------------------------------
// ==35418== 
// ==35418== Possible data race during write of size 4 at 0x10C158 by thread #3
// ==35418== Locks held: none
// ==35418==    at 0x1092DA: incrementCounter() (thread_debug.cpp:9)
// ==35418==    by 0x109C06: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:61)
// ==35418==    by 0x109BB2: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:96)
// ==35418==    by 0x109B53: void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (std_thread.h:259)
// ==35418==    by 0x109B23: std::thread::_Invoker<std::tuple<void (*)()> >::operator()() (std_thread.h:266)
// ==35418==    by 0x109B03: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() (std_thread.h:211)
// ==35418==    by 0x4947252: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30)
// ==35418==    by 0x485396A: ??? (in /usr/libexec/valgrind/vgpreload_helgrind-amd64-linux.so)
// ==35418==    by 0x4B4BB42: start_thread (pthread_create.c:442)
// ==35418==    by 0x4BDCBB3: clone (clone.S:100)

#include <iostream>
#include <thread>
#include <mutex>

static int counter = 0;
// 线程不安全函数
void incrementCounter()
{
    counter++;
}

int main()
{
    std::thread t1(incrementCounter);
    std::thread t2(incrementCounter);

    t1.join();
    t2.join();

    std::cout << "Counter: " << counter << std::endl;

    return 0;
}
// check_memory.cpp

// 编译程序
// g++ check_memory.cpp -o check_memory -g

// 运行程序
// valgrind --leak-check=full --track-origins=yes -s ./check_memory
//  cg_annotate cachegrind.out.*

// 程序输出
// --------------------------------------------------------------------------------
// I1 cache:         32768 B, 64 B, 8-way associative
// D1 cache:         49152 B, 64 B, 12-way associative
// LL cache:         12582912 B, 64 B, 12-way associative
// Command:          ./cache_optimize
// Data file:        cachegrind.out.35767
// Events recorded:  Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
// Events shown:     Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
// Event sort order: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
// Thresholds:       0.1 100 100 100 100 100 100 100 100
// Include dirs:     
// User annotated:   
// Auto-annotation:  on
// ......

#include <iostream>

int main()
{
    int *ptr = new int(5);
    int a;

    // 内存越界读
    std::cout << ptr[6] << std::endl;

    // 内存越界写
    ptr[6] = 1;

    // 使用已经释放的内存
    std::cout << *ptr << std::endl;

    // 使用未初始化的变量
    std::cout << a << std::endl;

    // 内存泄漏
    ptr = new int(5);

    return 0;
}
相关推荐