堆管理器, copy-on-write, 动态链接库——我忽然想明白一个问题

堆管理器, copy-on-write, 动态链接库——我忽然想明白一个问题

用过C++ builder的同志应该对下面这则注释不陌生:
// ---------------------------------------------------------------------------
//    Important note about DLL memory management when your DLL uses the
//    static version of the RunTime Library:
//
//    If your DLL exports any functions that pass String objects (or structs/
//    classes containing nested Strings) as parameter or function results,
//    you will need to add the library MEMMGR.LIB to both the DLL project and
//    any other projects that use the DLL.  You will also need to use MEMMGR.LIB
//    if any other projects which use the DLL will be performing new or delete
//    operations on any non-TObject-derived classes which are exported from the
//    DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
//    EXE's to use the BORLNDMM.DLL as their memory manager.  In these cases,
//    the file BORLNDMM.DLL should be deployed along with your DLL.
//
//    To avoid using BORLNDMM.DLL, pass string information using "char *" or
//    ShortString parameters.
//
//    If your DLL uses the dynamic version of the RTL, you do not need to
//    explicitly add MEMMGR.LIB as this will be done implicitly for you
// ---------------------------------------------------------------------------

简单的说,你要在不同模块间传递String对象就要使用borlandmm.dll或者使用动态链接crt。

这则注释出现的很是地方,但是它的内容恐怕只能用“聊不如无”来形容。你要是忽视它,下场就是AccessViolation,你要是读了它并按他说的去做,下场多半仍然是AccessViolation。

归根结底,就是一个堆管理器问题。win32进程中每个模块有自己的本地堆,由自己堆管理器管理。管理器A申请的内存,由B来释放,必然会产生问题,所以注释中说互传String对象不安全。但问题是,不安全的可不仅仅是String对象,事实上所有使用copy-on-write技术的类都不安全,比如BCB自带的std::string。char *就安全么?Thousands times NO!除非你不在另一个模块delete它,动态RTL安全么?不知道,但如果是赌博的话我赌不安全,原因下面说。

上面是对问题的简单描述,相信来这里的朋友对这个问题应该是比较了解的,不细说了,如果要更详细的了解,可以到这里: http://www.codexterity.com/ ,里面有对这个问题的详细描述和解决方案。

说说我想明白的事情。
为什么在大多数情况下,使用动态链接的crt能避免这个问题呢?我一直在想,解决问题的唯一办法应该是让同一份crt代码执行内存的释放和申请工作。难道BCB能通过某个机制告诉dll内存操作函数的内存地址(这也不奇怪,据说BCB自己用的控件库文件bpl就是这样),问题是对于BCB编译出来的dll在release下除了那个恶心的__cppdebughook意外没发现什么附加接口啊。

刚才再往上看blog,忽然想起这个问题,才发现自己曾经进行过一次多么愚蠢的思考:结论显而易见——不同模块加载同一个crt的运行时dll,返回的是同一个副本,自然就统一了内存管理嘛。

这也就是我刚才赌不安全的原因——不同版本的crt怎么办?BCB6些的dll,要使用在BCB2009的工程中,我没测试过,估计2009的crt要有更新吧?这样就会出现多个内存管理器,下场见上文。

OK,我知道这是个特别无聊的事情,事实上把它下载一个技术网站里让大家看我都不禁有种“逼娼为良”的负罪感。其实我真正想讨论的是:问什么对于很多诸如此类白痴的问题,我经常想要好久才忽然明白呢?

//------------------------------------
update:
上文有一个错误, std::string的问题不在于cow机制,而在于它使用了allocator,感谢hsen的指正。

你可能感兴趣的:(堆管理器, copy-on-write, 动态链接库——我忽然想明白一个问题)