在Win32上增强icu u32_regex内存泄漏/缓存

boost with icu u32_regex memory leak / cache on Win32

本文关键字:内存 regex 泄漏 缓存 u32 Win32 增强 icu      更新时间:2023-10-16

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

有没有其他人看到这个,也许知道一种清除缓存的方法,以便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)

虽然我确实尝试了一个boost 1.42和icu 4.2.1,我碰巧在我的系统上建立了相同的结果,所以不要认为这是一个问题,可以通过更改为最新版本的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

为您的机器提供相应的headers/libs路径

复制相应的boost dll到包含test.exe的目录(boost_regx -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实际上是这里的罪魁祸首,因为它的名字在第二个块的开始。

只是做第一个测试(即只是创建一个标准regex而不是u32_regex)没有检测到内存泄漏。

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

我试图通过使用u_cleanup()调用清理icu缓存,按照icu文档参见icu初始化和终止部分。

然而,我不是很熟悉icu库(实际上我只是使用它,因为我们想要unicode感知regex支持),不能看到如何获得u_cleanup()调用来实际清理数据时icu是由boost regex dll加载。

重申一下问题似乎是:-

在可选的icu支持编译的dll中boost regex(我很确定这使用了一个静态链接到icu,但这里可能是错误的)

如果我链接到icucc。lib中的测试程序,以便我可以调用u_cleanup(),这似乎不会影响通过boost regex库加载的ICU实例所持有的内存(好吧,如果它确实会相当奇怪)

我在regex库中找不到任何调用,允许我要求它清理ICU数据,这是我们真正想要调用的地方。

u_cleanup是清理数据的,但是如果有任何项仍然打开,它不能清理数据。

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

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

既然我确实解决了这个问题(在boost用户的帮助下),我想我也可以在这里回答这个问题。

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

确保顺序的最简单方法是将单元测试框架作为一个静态库链接起来——然后在任何dll之后销毁它的对象,因此不会将缓存的对象报告为内存泄漏,因为它们已经被销毁了。