c++ - hboehm 垃圾收集器未初始化值错误和泄漏
问题描述
我正在试验hboehm 垃圾收集器,现在只是尝试运行他们的简单示例。问题是,当我用 Valgrind 检查结果时,我得到很多“使用未初始化值”的错误,而且具有讽刺意味的是,内存泄漏。
重现问题的最小示例的完整项目。
cmake_minimum_required(VERSION 3.10)
# This "outer" CMake file works as a dependency fetcher, and it consists almost exclusively of ExternalProject commands.
# The "inner" CMake file under project/ is a more traditional CMake file. It uses the find_* commands to locate
# dependencies without any knowledge or assumptions about where those dependencies live or how they got there.
include(ExternalProject)
ExternalProject_Add(
libatomic_ops
URL http://www.hboehm.info/gc/gc_source/libatomic_ops-7.6.2.tar.gz
CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ""
)
ExternalProject_Get_Property(libatomic_ops SOURCE_DIR)
set(libatomic_ops_SOURCE_DIR "${SOURCE_DIR}")
ExternalProject_Add(
hboehm_gc
URL http://www.hboehm.info/gc/gc_source/gc-7.6.4.tar.gz
DEPENDS libatomic_ops
BUILD_IN_SOURCE TRUE
# hboehm_gc requires libatomic_ops be placed in a libatomic_ops subdirectory
PATCH_COMMAND "${CMAKE_COMMAND}" -E copy_directory "${libatomic_ops_SOURCE_DIR}" "<SOURCE_DIR>/libatomic_ops"
CONFIGURE_COMMAND ./configure "--prefix=<INSTALL_DIR>"
BUILD_COMMAND make
INSTALL_COMMAND make install
)
ExternalProject_Get_Property(hboehm_gc INSTALL_DIR)
set(hboehm_gc_INSTALL_DIR "${INSTALL_DIR}")
# Now that we have our dependencies on disk to be found, it's safe to configure (run cmake on) the real project
ExternalProject_Add(
main DEPENDS hboehm_gc
DOWNLOAD_COMMAND ""
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/project"
BUILD_ALWAYS TRUE
CMAKE_ARGS "-DCMAKE_PREFIX_PATH=${hboehm_gc_INSTALL_DIR}"
INSTALL_COMMAND ""
TEST_COMMAND "${CMAKE_CTEST_COMMAND}" --verbose
)
cmake_minimum_required(VERSION 3.10)
find_path(HBOEHM_GC_INSTALL_DIR include/gc.h)
find_program(VALGRIND_COMMAND valgrind)
add_executable(main src/main.cpp)
target_compile_features(main PRIVATE cxx_std_14)
target_link_libraries(main PRIVATE "${HBOEHM_GC_INSTALL_DIR}/lib/libgc.a" pthread)
target_include_directories(main PRIVATE "${HBOEHM_GC_INSTALL_DIR}/include")
enable_testing()
add_test(NAME valgrind COMMAND "${VALGRIND_COMMAND}" "$<TARGET_FILE:main>")
set_tests_properties(
valgrind PROPERTIES
PASS_REGULAR_EXPRESSION "ERROR SUMMARY: 0 errors from 0 contexts"
)
#include <cassert>
#include <iostream>
#include <gc.h>
int main() {
int i;
GC_INIT(); /* Optional on Linux/X86; see below. */
for (i = 0; i < 10000000; ++i)
{
int **p = (int **) GC_MALLOC(sizeof(int *));
int *q = (int *) GC_MALLOC_ATOMIC(sizeof(int));
assert(*p == 0);
*p = (int *) GC_REALLOC(q, 2 * sizeof(int));
if (i % 100000 == 0)
std::cout << "Heap size = " << GC_get_heap_size() << "\n";
}
return 0;
}
只需要:
mkdir build
cd build
cmake ..
make
它将下载 hboehm_gc 和依赖项,构建项目并运行 valgrind。我希望我只是以某种方式滥用图书馆,但我不确定我做错了什么。任何帮助表示赞赏。
解决方案
您应该期望 Boehm 的收集器有一些内存泄漏(因为它是一个保守的GC)。由于 Boehm GC 是一个保守的 GC,它不(也不能)提供强有力的保证。但是你希望它不会有太多的泄漏或内存浪费(一些论文提到了 20% 的泄漏率,这是 Boehm 在 Linux/x86-64 上的 GC 的典型表现)。Boehm 的 GC 有一个关于保守垃圾收集的优点和缺点的页面,你绝对应该阅读。还有对它的详细描述,最后它是免费软件,所以你可以(也许应该)研究它的源代码。
Boehm 和 valgrind 都使用类似的技术,因此它们不能很好地配合使用。显然 valgrind 会在使用 Boehm GC 的任何代码中检测到大量内存泄漏。在链接 Boehm 的 GC 的代码上使用 valgrind 是没有用的。您可以明确清除使用GC_MALLOC
.
如果您需要精确的 GC(特别是如果您需要更多关于 GC 的保证),请选择其他东西,或者编写自己的代码(天真的精确标记和扫描 stop-the-world GC 很容易编码,至少在单线程中)程序;无聊的部分是维护 GC 根并提供对包含指针的本地“变量”的访问。您将struct
在每个调用帧中将它们放在一些中,并将这些struct
-s 链接在一起)。也许看看Ravenbrook 的 MPS,或者我的旧的、无人维护的、有缺陷的Qish(也许它可以激发你的灵感)。还要查看Ocaml GC 以及如何将C 与 Ocaml 接口。
另请阅读GC 手册。
顺便说一句,您的问题令人惊讶:valgrind(它的memcheck工具)用于寻找丢失的 -s,而 Boehm GC 的全部目的是通过提供不需要任何类型的释放操作的(替换)free
来呈现free
“无用” (所以在执行-s的程序上使用 valgrind 是没有意义的)。GC_MALLOC
malloc
GC_MALLOC
推荐阅读
- python - 用 for 循环填充字典
- mysql - mysql group by, max, count 实现
- c - 将共享库与 libm 链接
- c++ - 静态链接到 VC++ 运行时,同时包含动态链接到它的静态库
- reactjs - 使用变量反应 Typescript 访问枚举值
- c# - Visual Studio 安装项目:在没有管理员权限的情况下运行 msi 安装程序
- python - 保存嵌套列表理解的结果
- android - 你如何设置一个裸工作流反应原生项目?
- python - 如何并行运行多个开放式 AI 健身房环境
- flutter - 如何访问存储在 Future 中的数据
在 FutureBuilder