C++ dll堆内存分配问题

C++ dll heap memory allocation issue

从这个,我知道我们(应用程序)应该始终不要从dll中删除堆内存分配,因为堆内存管理器是不同的.

我有几个问题:

1.) .so文件呢(Linux),是不是一样的情况?

2.) 是否有办法确保应用程序和库(.dll 和 .so)使用相同的堆内存管理器或使用相同的堆内存部分?所以我们可以分别delete和new(new在.dll/.so,delete在application)。

谢谢。

1) Linux 中的整个进程共享符号表。 malloc() 的任何部分 过程与所有其他部分相同。所以是的,如果进程的所有部分都访问 通过 malloc() 等堆,然后它们将共享同一个堆。

2) 但第二个问题我也有点困惑。

堆管理器位于运行时库的静态内存中(Win 为 msvcrXXX,Linux 为 crt)。您可以通过两种方式使用运行时库:静态或动态。如果您 link 运行时对于您自己的库是静态的,那么您不能在您的库中分配并在另一个库中释放。但是你 link 运行时是动态的,那么你可以在你的库中分配并在另一个库中释放。

1.) How about .so file (Linux), is it the same case ?

是的,使用标准 C++ 库的不同实现构建的库与其最终链接的程序可能会以稍微不同的方式进行分配。 g++libstdc++clang++libc++ 是两种不同实现的示例。它们可能 100% ABI 兼容 - 但第三个未知库可能不是。

2.) Is there anyway to make sure that application and library(.dll and .so) are using same heap memory manager or using same heap memory section ? So we can delete and new separately (new at .dll/.so, delete at application ).

不,编译到库中的就是库将使用的,除非有一种方法可以在加载库时初始化库,告诉它使用特定的堆管理器。

Please explain in details. I wish to know for .so (Linux), is it using only one heap manager for both application and .so (library). Let's said, my application compiled by compiler version A, while my .so complied by compiler version B, is it still ok ?

因为上面提到的原因,不,你不能确定。由于您是库的创建者,因此您可以创建 API 以便将库中类型的 newdelete 内存 allocations/deallocations 委托给编译到库中的成员函数,这反过来又做了真正的 allocations/deallocations (在 operator new, operator new[] 中描述 和 operator delete, operator delete[])。然后可以 new 编辑并在库和应用程序之间传递指向您的类型的对象的指针,并在任一侧 deleted。


这是一个(不完整的)示例,说明使用 class 特定的分配函数:
void* T::operator new(std::size_t count);

和一个class-特定的常用释放函数:
void T::operator delete(void* ptr);

它包含 foo.hppfoo.cpp 用于创建 libfoo.so(或 libfoo.a)和使用该库的程序的代码。

foo.hpp

#pragma once

#include <new>

class Foo {
public:
    // The "usual" part of your class definition:
    Foo(int x);
    ~Foo();

    // This part does NOT get compiled into your library.
    // It'll only be used by users of your library:
#ifndef BUILDING_LIB
    // Note: operator new and delete are static by default

    // single object allocation/deallocation:
    void* operator new(std::size_t /* byte_count */) { return Alloc(); }
    void operator delete(void* addr) { Free(addr); }

    // array allocation/deallocation:
    // TODO: operator new[] and delete[]
#endif
private:
    int value;

    // the functions really doing the memory management
    static void* Alloc();
    static void Free(void* p);
};

foo.cpp

// Define BUILDING_LIB to disable the proxy operator new/delete functions when building
// the library.
#define BUILDING_LIB
#include "foo.hpp"

#include <cstdlib> // std::aligned_alloc
#include <iostream>

Foo::Foo(int x) : value(x) {
    std::cout << "Foo:Foo(" << value << ")\n";
}

Foo::~Foo() {
    std::cout << "Foo:~Foo() " << value << "\n";
}

void* Foo::Alloc() {
    void* addr = std::aligned_alloc(alignof(Foo), sizeof(Foo));
    std::cout << "Alloc() " << sizeof(Foo) << "\t@ " << addr << '\n';
    return addr;
}

void Foo::Free(void* addr) {
    std::cout << "Free()\t\t@ " << addr << '\n';
    std::free(addr);
}

uselib.cpp

#include "foo.hpp"

#include <memory>

int main() {
    auto a = std::make_unique<Foo>(123); // heap allocation

    // An automatic variable will use the applications memory manager and will not
    // use Alloc/Free.
    Foo b(456);
}

可能的输出:

Alloc() 4       @ 0x1af7eb0
Foo:Foo(123)
Foo:Foo(456)
Foo:~Foo() 456
Foo:~Foo() 123
Free()          @ 0x1af7eb0

库开发人员通过实施他们自己的方法来释放库内部分配的内存来解决这个问题。 例如:

  • OpenIPMI 调用 ipmi_fru_node_get_fieldipmi_fru_data_free.
  • CryptoAPI 调用 CertCreateCertificateContextCertFreeCertificateContext