从这个链接中,我了解到我们(应用程序)应该不要从dll中删除堆内存分配,因为堆内存管理器是不同的。
我有几个问题:
1.) 那么在Linux上,.so文件是否也是如此?
2.) 是否有任何方法来确保应用程序和库(.dll和.so)使用相同的堆内存管理器或使用相同的堆内存段?这样我们就可以分别进行删除和新建(在.dll/.so中新建,在应用程序中删除)。
谢谢。
从这个链接中,我了解到我们(应用程序)应该不要从dll中删除堆内存分配,因为堆内存管理器是不同的。
我有几个问题:
1.) 那么在Linux上,.so文件是否也是如此?
2.) 是否有任何方法来确保应用程序和库(.dll和.so)使用相同的堆内存管理器或使用相同的堆内存段?这样我们就可以分别进行删除和新建(在.dll/.so中新建,在应用程序中删除)。
谢谢。
1.) .so文件(Linux)如何呢?情况是否相同?
是的,使用与程序最终链接的标准C++库不同的实现构建的库可能以稍微不同的方式分配内存。 g ++
的 libstdc ++
和 clang ++ 的
libc ++ 是两个不同实现的示例。 它们可能是100% ABI兼容的-但第三个未知库可能不是。
2.) 有没有办法确保应用程序和库(.dll和.so)正在使用相同的堆内存管理器或正在使用相同的堆内存部分?因此我们可以分别删除和新建(在.dll / .so上进行新建,在应用程序中进行删除)。
不行的,除非有一种方法在加载库时初始化它,告诉它使用特定的堆管理器,否则编译进库的内容将由库使用。
请详细解释。我希望了解.so(Linux),它是否仅为应用程序和.so(库)使用一个堆管理器。让我们说,我的应用程序由编译器版本A编译,而我的.so由编译器版本B编译,还可以吗?
由于上述原因,不行的,你无法确定。但你作为库的创建者,可以将API制作成这样,即将库中类型的new
和delete
内存分配/释放委托给编译到库中并执行实际分配/取消分配(在 operator new,operator new[]
和operator delete,operator delete[]中描述)。然后可以new
指向对象的指针,并在库和应用程序之间传递,并在两边delete
。
下面是使用类特定分配函数:
void* T :: operator new(std :: size_t count);
以及类特定常规释放函数:
void T :: operator delete(void * ptr);
它包含用于创建libfoo.so
(或libfoo.a
)的foo.hpp
和foo.cpp
的代码以及使用库的程序的代码。
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
1) 在Linux中,符号表在整个进程中共享。对于进程的任何部分而言,malloc()与所有其他部分相同。因此,如果进程的所有部分都通过malloc()等方式访问堆,则它们将共享同一个堆。
2) 但第二个问题我也有点困惑。