跨 dll 边界的内存分配和释放

发布于 2024-08-04 00:15:09 字数 879 浏览 1 评论 0原文

我知道在一个 dll 中进行内存分配然后在另一个 dll 中释放内存可能会导致各种问题,尤其是与 CRT 相关的问题。当涉及到导出 STL 容器时,此类问题尤其成问题。我们以前遇到过这类问题(在编写与我们的库链接的自定义 Adob​​e 插件时),并且我们通过定义我们在所有容器中使用的自己的分配器来解决这些问题,例如

typedef std::vector < SessionFields, 
        OurAllocator < SessionFields > > 
        VectorSessionFields;

typedef std::set < SessionFields, 
        std::less < SessionFields >, 
        OurAllocator < SessionFields > > 
        SetSessionFields;

:类型传入/传出我们的代码,但是我们遇到了一个问题,因为我们现在必须调用 Adob​​e SDK 中的一个函数,该函数返回一个填充向量,当它超出范围时会导致崩溃。

显然,当 Adob​​e 的 SDK 中的内存最终在我的代码中释放时,内存被分配到属于不同的堆,这是一个问题。所以我想也许我可以做一些聪明的事情,比如以某种方式覆盖或导出他们的 SDK 中使用的分配器,这样我就可以用它来清理从其函数返回的容器。

我还在考虑编写一个包装器或某种类型的 thunking 层,以便 STL 容器可以在我的代码和 SDK 之间安全地编组(尽管这听起来确实很混乱)。

另外,我还考虑使用 GetProcessHeaps 来识别 SDK 中使用的堆,并尝试释放该堆(而不是默认堆)。

有人对我们如何解决这个问题有任何建议吗?

I understand that memory allocations made in one dll then subsequently free'd in another can cause all sort of problems, especially regarding the CRT. These sorts of problems are especially problematic when it comes to exporting STL containers. We've experienced these sorts of problems before (when writing custom Adobe plugins that linked with our libraries) and we've worked round these issues by defining our own allocator that we use in all our containers, eg:

typedef std::vector < SessionFields, 
        OurAllocator < SessionFields > > 
        VectorSessionFields;

typedef std::set < SessionFields, 
        std::less < SessionFields >, 
        OurAllocator < SessionFields > > 
        SetSessionFields;

This has worked well when passing types to/from our code, however we've hit a problem in that we're now having to call a function in Adobe's SDK that returns a populated vector which causes a crash when it goes out of scope.

Obviously, it's a problem with memory being allocated in Adobe's SDK belonging to a different heap when it's finally free'd in my code. So I'm thinking that maybe I could do something clever like somehow overriding or exporting the allocator used in their SDK so I could use it to clean up containers returned from their functions.

I'm also looking at writing a wrapper or some sort of thunking layer whereby STL containers would be safely marshalled between my code and the SDK (although this does sound very messy).

Alternatively, I'm also looking at using GetProcessHeaps to identify the heap used from within the SDK, and try to free against this heap, instead of the default heap.

Has anyone any advice on how we can solve this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

青春如此纠结 2024-08-11 00:15:09

讽刺的是,Adobe Source Libraries 有一个 adobe::capture_allocator 类这是专门为这种 DLL 安全性而编写的。它的工作方式是在实例化时捕获本地 newdelete ,并在对象的生命周期中携带它们。 (有关如何执行此操作的详细信息,请参阅 adobe::new_delete_t,尤其是此处的实现。)通过捕获的删除 例程,保证无论您身在何处,都可以使用正确的删除进行删除。

您可以看到 version_1capture_allocator > Adob​​e Source Libraries 中的类型,例如 adobe::any_regular_tadobe::copy_on_writecapture_allocator 也应该与所有 STL 容器类型兼容。

更新:capture_allocator 不符合标准,因为它保留状态。这不应该成为其可用性的大障碍,但这确实意味着不能保证它的使用能够与符合标准的容器一起使用。

Ironically enough, the Adobe Source Libraries has a adobe::capture_allocator class that was written specifically with this kind of DLL safety in mind. The way it works is to capture the local new and delete at this point it is instantiated, and to carry them both around for the lifetime of the object. (See adobe::new_delete_t for details on how it does this, especially the implementation here.) Deallocations take place with the captured delete routine, guaranteeing that no matter where you are you are deleting with the proper delete.

You can see capture_allocator used throughout the version_1 types in the Adobe Source Libraries, such as adobe::any_regular_t and adobe::copy_on_write. capture_allocator should be compatible with all STL container types as well.

Update: capture_allocator is not standard-compliant because it retains state. This should not be a big hindrance to its usability, but it does mean its use is not guaranteed to work with standard-compliant containers.

失与倦" 2024-08-11 00:15:09

目前我们正在开发一个 dll,它通过 C 接口公开 C++ 功能(为了 C# 能够使用所述 dll)。

例如:dll 有一个 struct myStruct_s 接口公开以下函数:

interface.h

#ifndef INTERFACE_TYPES_H
# error Please include interace_types.h
#endif
    myStruct_s * CreateTheStruct() { return new myStruct_s(); }
    void DestroyTheStruct(myStruct_s * the_struct) { delete the_struct; }
    void DoSomethingToTheStruct(myStruct_s * the_struct);

interface_types.h

#define INTERFACE_TYPES_H
struct myStruct_s; // fwd declaration
#endif

interface.cpp

#if defined(__CPPPLUS) || defined(__cplusplus) || defined (__CPLUSPLUS)
#include<TheRealFileContainingTheRealMyStruct_s.h>
// handle the .h's functions here
#endif

comeOutsideCppFile .cpp

#include "interface_types.h"
#include "interface.h"

void main()
{
    myStuct_s * x = CreateTheStruct;
    DoSomethingToTheStruct(x);
    DestroyTheStruct(x);
}

上面是我们的东西如何工作的粗略概述,基本上是:
无论 dll 公开什么,都需要:创建、处理、销毁 dll 端

此代码不是 100% 准确!

另外,请记住,如果您使用纯 C++ dll,则可能需要与用于构建 dll 的编译器具有相同设置的相同编译器。

At the moment we're working on a dll which exposes C++ functionality via a C interface (for the sake of C# being capable of using the said dll).

for instance : the dll has a struct myStruct_s the interface exposes the following functions :

interface.h

#ifndef INTERFACE_TYPES_H
# error Please include interace_types.h
#endif
    myStruct_s * CreateTheStruct() { return new myStruct_s(); }
    void DestroyTheStruct(myStruct_s * the_struct) { delete the_struct; }
    void DoSomethingToTheStruct(myStruct_s * the_struct);

interface_types.h

#define INTERFACE_TYPES_H
struct myStruct_s; // fwd declaration
#endif

interface.cpp

#if defined(__CPPPLUS) || defined(__cplusplus) || defined (__CPLUSPLUS)
#include<TheRealFileContainingTheRealMyStruct_s.h>
// handle the .h's functions here
#endif

comeOutsideCppFile.cpp

#include "interface_types.h"
#include "interface.h"

void main()
{
    myStuct_s * x = CreateTheStruct;
    DoSomethingToTheStruct(x);
    DestroyTheStruct(x);
}

The above is a rough outline of how our stuff works, basically :
Whatever the dll exposes needs to be : Created, Handled, Destroyed dll-side

This code is not 100% accurate!!!

Also, please keep in mind that if you're using a pure C++ dll, you probably need the same compiler with the same settings as the one used to build the dll.

未蓝澄海的烟 2024-08-11 00:15:09

您可能会尝试查看是否存在任何正式的 C++ 规则来说明当异常在一个 DLL 中引发并在另一个 DLL 中捕获然后超出范围时会发生什么情况 - 看起来非常相似。对于例外情况,我认为您需要提供带有特殊签名的复制构造函数,尽管我现在不确定它到底是什么。

You might try looking to see if there are any formal C++ rules for what happens when an exception is thrown in one DLL and caught in another and then goes out of scope -- it seems very similar. For exceptions, I think you are required to provide a copy constructor with a special signature, though I'm unsure now exactly what it is.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文