【问题标题】:boost with icu u32_regex memory leak / cache on Win32在 Win32 上使用 icu u32_regex 内存泄漏/缓存来提升
【发布时间】:2011-10-15 14:38:14
【问题描述】:

在启用可选 ICU 支持的情况下使用 boost regex 类时(有关详细信息,请参阅boost documentation),我似乎遇到了内存泄漏,或者更确切地说,发生了某种我似乎无法重置/清理的内存缓存。

有没有其他人看到这个并且可能知道清除缓存以使 boost 单元测试框架不会报告内存泄漏的方法?

我的问题的详细信息是:-

ICU version 4.6.0
(Built using supplied vs2010 solution in debug and release configuration)
Boost version 1.45
(built with command "bjam variant=debug,release threading=multi link=shared stage" since standard distribution does not include icu support in regex)
OS Windows 7
Compiler MSVC 10 (Visual Studio 2010 Premium)

虽然我确实尝试过使用 icu 4.2.1 的 boost 1.42,但我碰巧在我的系统上构建了相同的结果,所以不要认为这是一个可以通过更改为 boost 1.47 icu 4.8.1 来解决的问题这是最新版本。

编译以下代码(Test.cpp):-

#define BOOST_TEST_MAIN    //Ask boost unit test framework to create a main for us
#define BOOST_ALL_DYN_LINK //Ask boost to link to dynamic library rather than purely header support where appropriate
#include <boost/test/auto_unit_test.hpp>

#include <boost/regex.hpp>
#include <boost/regex/icu.hpp> //We use icu extensions to regex to support unicode searches on utf-8
#include <unicode/uclean.h>    //We want to be able to clean up ICU cached objects

BOOST_AUTO_TEST_CASE( standard_regex ) 
{
    boost::regex re( "\\d{3}");
}

BOOST_AUTO_TEST_CASE( u32_regex ) 
{
    boost::u32regex re( boost::make_u32regex("\\d{3}"));
    u_cleanup(); //Ask the ICU library to clean up any cached memory
}

可以通过以下方式从命令行编译:-

C:\>cl test.cpp /I[BOOST HEADERS PATH] /I[ICU HEADERS] /EHsc /MDd -link /LIBPATH:[BOOST LIB PATH] [ICU LIB PATH]icuuc.lib

为您的机器提供适当的头文件/库路径

如果没有路径,则将相应的 boost dll 复制到包含 test.exe 的目录(boost_regex-vc100-mt-gd-1_45.dll 和 boost_unit_test_framework-vc100-mt-gd-1_45.dll)

运行上述步骤中的 test.exe 时,我得到:-

Running 2 test cases...

*** No errors detected
Detected memory leaks!
Dumping objects ->
{789} normal block at 0x00410E88, 28 bytes long.
 Data: <    0N U        > 00 00 00 00 30 4E CD 55 00 00 00 00 01 00 00 00
{788} normal block at 0x00416350, 14 bytes long.
 Data: <icudt46l-coll > 69 63 75 64 74 34 36 6C 2D 63 6F 6C 6C 00
{787} normal block at 0x00415A58, 5 bytes long.
 Data: <root > 72 6F 6F 74 00
...lots of other blocks removed for clarity ...

我猜 icu 实际上是这里的罪魁祸首,因为它的名字位于第 2 个区块的开头。

仅进行第一次测试(即仅创建标准正则表达式而不是 u32_regex)未检测到内存泄漏。

在测试中添加多个 u32_regex 不会导致更多内存泄漏。

我尝试按照icu documentation 使用 u_cleanup() 调用来清理 icu 缓存,请参阅 ICU 初始化和终止部分。

但是我对 icu 库不是很熟悉(实际上我只是在使用它,因为我们想要支持 unicode 的正则表达式支持)并且看不到如何在 ICU 运行时调用 u_cleanup() 来实际清理数据由 boost regex dll 加载。

只是重申问题似乎是:-

在使用可选 icu 支持编译的 dll 中提升正则表达式(我很确定这使用到 icu 的静态链接,但这里可能是错误的)

如果我在测试程序中链接到 icuuc.lib 以便我可以调用 u_cleanup() 这似乎不会影响通过 boost 正则表达式库加载的 ICU 实例所持有的内存(如果确实)

我在 regex 库中找不到任何调用,可以让我请求它清理我们真正想要调用的 ICU 数据。

【问题讨论】:

    标签: c++ dll icu boost-regex


    【解决方案1】:

    只是想我不妨在这里回答这个问题,因为我确实解决了这个问题(在 boost 用户的帮助下)。

    问题在于拆除的顺序 - 如果 boost regex dll 中的静态对象在单元测试框架之前没有被破坏,那么这仍然会缓存一些数据。因此 UTF 报告内存泄漏。仅仅调用 u_cleanup() 是不够的。

    确保顺序的最简单方法是将单元测试框架作为静态库链接 - 然后在任何 dll 之后破坏其对象,因此不会将缓存的对象报告为内存泄漏,因为它们已经被破坏.

    【讨论】:

      【解决方案2】:

      u_cleanup 是清理数据的对象,但是如果任何项目仍处于打开状态,则无法清理数据。

      您可以尝试不调用任何 boost 函数,而只调用 u_cleanup() 并查看是否有任何泄漏?然后尝试调用u_init() 然后u_cleanup()

      我不熟悉 Boost,不知道上面的代码是否会清理正则表达式,或者 boost 是否有任何内部缓存。泄漏的对象看起来不像通常的 ICU 数据,如果 ICU 的数据仍然打开,您会看到相当多的数据,而不是 14+5 字节

      【讨论】:

      • 谢谢——这只是泄露数据的开始——我已经编辑了这个问题,希望能让问题更清楚。
      • 进一步调查表明,icu 实际上是动态链接而不是静态链接。如果找不到 icu dll,Boost 正则表达式似乎会优雅地降级,这就是为什么删除 icu dll 不会生成 dll not found 消息(这是我查看动态或静态链接的简单测试)。因此 u_cleanup() 应该可以工作(我认为)
      • 如果您在构建 ICU 时将预处理器标志 UCLN_NO_AUTO_CLEANUP 定义为 0(您可以在 uconfig.h 的顶部添加 #define ),那么 ICU 将在卸载 DLL 时自行清理。如果 ICU 已清理或从未加载,则调用 u_cleanup 是安全的。
      猜你喜欢
      • 1970-01-01
      • 2015-03-20
      • 2014-12-30
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多