使用Google测试框架(不是Windows)进行内存泄漏检测的标准做法是什么

问题描述 投票:0回答:2

我使用 Google Test 进行了大量的单元测试。

目前使用 XCode,我注意到其他一些测试框架会在每个单元测试结束时检测内存泄漏,并且我认为有一种规定的方法可以使用 Google Test 执行相同的操作。我希望这不仅仅是 Boost Test 和其他一些功能的功能。

如果有人能指出我正确的方向,我将不胜感激。而是避免切换测试框架。

现在,我认为 valgrind 可能值得研究,我只是不确定如何参与每个测试。我的猜测是我无法直接从 xcode 执行此操作。

c++ xcode memory-leaks googletest
2个回答
7
投票

据我所知,Google Test 中并未明确支持内存泄漏的单元测试。不过,您有这个扩展可以为您填补该部分


0
投票

我发现使用 gperf 的工具 - 堆检查器(也是由 Google 提供) 非常强大,同时也易于使用(至少在其非常基本的形式中)。

  1. 前言:为了简化(从我的角度来看)与安装、链接和包含简单程序所需的包有关的所有“后勤”,我正在使用

    cmake
    工具。

  2. 物流:我正在使用 Ubuntu 22.04 64 位以及

    glibc 2.35
    gcc 11.04
    cmake 3.22.1
    。 要安装
    cmake
    ,请运行:
    sudo apt-get install cmake
    。 其余的可能存在于您的 Linux 发行版上。

  3. 安装

    gperf
    软件包以及
    tcmalloc
    :为了使用 gperf 软件包,应该像这样安装:
    sudo apt-get install google-perftools libgoogle-perftools-dev
    。 安装软件包后,您将在以下位置找到其
    .so
    文件:
    /usr/lib/x86_64-linux-gnu/libtcmalloc.so.4
    。 让链接器知道库位置的一种方法是在
    /lib/x86_64-linux-gnu
    下创建指向它的符号链接。 另外,请确保在
    /usr/include/gperftools/
    下有
    heap-checker.h
    文件。 注意:
    tcmalloc
    是 Google 实施的版本,用于替换(如果需要/期望)
    glibc
    malloc
    。可以在这里找到。 另请注意,如果您希望保持
    glibc
    的正常状态
    malloc
    ,您可以这样做(您不必将应用程序本身的可执行文件链接到
    tcmalloc
    )。

  4. 源文件: 我为此示例编写的最少代码采用以下“结构”:

    ├──构建(文件夹)

    ├── CMakeLists.txt

    └──unitTestsMain.cpp

  5. unitTestsMain.cpp:下面是一个非常简单且纤薄的C++对象,在其实现中存在内存泄漏。此外,还有

    createSingleMySampleObject
    GTest 单元测试函数来说明
    heap_checker
    如何捕获内存泄漏。

    #include <iostream>
    #include <gtest/gtest.h>        
    #include <gperftools/heap-checker.h>

    using namespace std;

    class MySampleObject
    {
        public:
            MySampleObject(int i, short s)
            {
                m_i = new int;
                m_s = new short;
                *m_i = i;
                *m_s = s;
            }

            ~MySampleObject()
            {
                delete m_i;
                //delete m_s; --> this is the itentional memory leak!
            }

            int *m_i;
            short *m_s;
    };

    TEST(sampleObjectTest, createSingleMySampleObject)
    { 
        cout << "sampleObjectTest::createSingleMySampleObject - start" << endl;
        HeapLeakChecker heap_checker("test_MySampleObject");
        {
            MySampleObject* pTestedObj = new MySampleObject(12, 17);
            delete pTestedObj;
        }
        if (!heap_checker.NoLeaks()) assert(NULL == "heap memory leak");
        cout << "sampleObjectTest::createSingleMySampleObject - end" << endl;
    }

    int main(int argc, char **argv)
    {
        testing::InitGoogleTest(&argc, argv);
        cout << "main - START of unit tests" << endl;
        int unitTestRetCode = RUN_ALL_TESTS();
        cout << "main - END of unit tests" << endl;
        return unitTestRetCode;
    }
  1. CMakeLists.txt
project(SampleUnitTestWithTcmallocAndGtest)
message(STATUS "unit tests CMakeLists.txt of ${CMAKE_PROJECT_NAME}")
cmake_minimum_required(VERSION 3.22.1)
set(CMAKE_CXX_STANDARD 20) # Add/customize global project settings:

# Locate GTest
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
 
# Link runTests with what we want to test and the GTest and pthread library
find_library(GTEST_LIBRARY gtest HINTS /usr/lib)

set(testsExeName "unitTests.out")
# unitTestsMain.cpp is the only source file used in this "mini project" (will be shown later)
add_executable(${testsExeName} unitTestsMain.cpp)

# Add the binary tree to the search path for include files
# so that we will find the heap-checker.h (for example)
target_include_directories(${testsExeName} PUBLIC /usr/include/gperftools)

# NOTES:
# tcmalloc - is linked in order to use tcmalloc in the unit tests instead of glibc malloc - only
# for the sake of using the heap checker feature of the tcmalloc library.
# pthread - is plain GTest requierment
target_link_libraries(${testsExeName} ${GTEST_LIBRARY} tcmalloc pthread)
  1. 构建: 为了构建这个简单的单元测试 main + 示例对象 + 其测试,请执行以下操作:

    cd build && cmake ../ && make

  2. 运行测试(有泄漏): 在

    build
    文件夹中执行以下操作:
    env HEAPCHECK=local ./unitTests.out

您应该期望输出如下:

WARNING: Perftools heap leak checker is active -- Performance may suffer
main - START of unit tests
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from sampleObjectTest
[ RUN      ] sampleObjectTest.createSingleMySampleObject
sampleObjectTest::createSingleMySampleObject - start
Have memory regions w/o callers: might report false leaks
Leak check test_MySampleObject detected leaks of 2 bytes in 1 objects
The 1 largest leaks:
Leak of 2 bytes in 1 objects allocated from:
        @ 645d6b089313
        @ 645d6b088d2c
        @ 645d6b0c8ecd
        @ 645d6b0c0b6d
        @ 645d6b0938ac
        @ 645d6b09433a

If the preceding stack traces are not enough to find the leaks, try running THIS shell command:

pprof ./unitTests.out "/tmp/unitTests.out.9512.test_MySampleObject-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv

If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might h
unitTests.out: /home/guya/dev/tmpFolder/unitTestsMain.cpp:36: virtual void sampleObjectTest_createSingleMySampleObject_Test::TestBody(): Assertion `NULL == "heap memory leak"' failed.
Aborted (core dumped)
  1. 解决泄漏并重新构建: 删除析构函数中导致泄漏的注释,并从
    build
    文件夹中运行
    make
    ,然后像以前一样重新运行测试。 您期望得到以下输出:
WARNING: Perftools heap leak checker is active -- Performance may suffer
main - START of unit tests
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from sampleObjectTest
[ RUN      ] sampleObjectTest.createSingleMySampleObject
sampleObjectTest::createSingleMySampleObject - start
Have memory regions w/o callers: might report false leaks
No leaks found for check "test_MySampleObject" (but no 100% guarantee that there aren't any): found 38 reachable heap objects of 76941 bytes
sampleObjectTest::createSingleMySampleObject - end
[       OK ] sampleObjectTest.createSingleMySampleObject (4 ms)
[----------] 1 test from sampleObjectTest (4 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (4 ms total)
[  PASSED  ] 1 test.
main - END of unit tests
© www.soinside.com 2019 - 2024. All rights reserved.