在动态加载的库中,我的内存分配在哪里?
Posted
技术标签:
【中文标题】在动态加载的库中,我的内存分配在哪里?【英文标题】:Where is allocated my memory in a dynamically loaded library? 【发布时间】:2014-07-08 14:47:51 【问题描述】:我想了很久。。 根据这张表: http://ilay.org/yann/articles/mem/process_map.png(对不起法语部分) 内存分配在不同的内存空间中,具体取决于程序的哪个部分正在分配它。
因此,如果我在我的程序中创建一个对象,它将在程序中分配。如果动态分配内存,它将在堆中,并且是动态加载对象的“链接”。
我的问题是: 从动态加载的库中动态分配的内存属于哪里?
如果我有包含这个的库:
extern "C" Object* create_Object()
return new Object();
class Object
int a;
int* b;
...
我的对象会分配在堆中还是链接中?
我的猜测是堆,但我有一段代码让我怀疑它。 我正在开发一个 Cpp 脚本系统,其中我的脚本被编译为共享库,加载到我的程序中,并在每次必须重新编译脚本时重新加载。这个想法是在卸载它们之前保存我的脚本的状态,并在动态加载的对象的新实例中恢复它们的内容。如果我的动态加载对象的字段映射在堆中,保存指向数据的指针就足够了,但是如果创建的类分配在内存的“链接”段中,那么当我恢复内容时,我的指针会指向在未分配的内存上,这将使我的程序完全不稳定,就是这种情况......
所以我不知道。我的“对象”实例在内存中的哪个位置? “a”在哪里,不是动态分配的?在我的示例中,如果我动态分配它,“b”的内容会在哪里?
我希望无论在哪里调用 new,new 都会在堆中分配,并且来自 Object 的变量 a 和 b 也将在堆中分配,因为它是从动态分配的对象实例化的,但它是只是猜测,我很想知道......
我也想知道一旦我关闭了我的共享库,我的 Object 实例会发生什么。再一次,如果它在堆中,访问我的对象应该没有任何问题,但由于我没有符号,我猜该对象将被分配但非常不合适,因为我无法解析它的成员.
希望你能帮我解决这个问题=)
【问题讨论】:
我认为,除非您重新定义对象分配器,否则new
在堆上分配。
也许你在调用这个对象的方法时会遇到问题。我不知道 C++ 的内部工作原理,但我希望该对象以某种方式具有指向定义类或其方法的完整表的副本的指针。这些指针将悬空。当然,这适用于虚方法。
【参考方案1】:
我认为对象数据安全地存储在堆上,即使在dlclose()
之后(除非 C++ 动态空间分配器已更改)。
但你肯定会遇到调用虚方法的问题。虚拟表将指向不再可用的文本区域。并且 C++ 没有提供重新绑定虚方法的方法;我不知道。
如果你真的需要,你可以:
-
将您的类定义更改为
struct
;
将所有虚方法声明为该结构内的指针;
让您的加载/卸载例程提供绑定(即,为每个分配对象中的每个指针分配每个实际函数)。
当然,您将跟踪所有对象实例。当然你可以有一个指针,指向一个表,这个表本身由库提供;不过,这个单指针仍然必须手动反弹。
【讨论】:
【参考方案2】:没有像从动态加载的库中动态分配的内存这样的东西。动态分配的内存意味着它是通过调用malloc
分配的。您的程序中只有一个malloc
,对它的调用是来自程序代码的一部分,该部分是与您的原始可执行文件一起加载的,还是与一个可共享的目标文件一起加载的,这并不重要。
注意:从实际的角度来看,new
通常是通过调用malloc
来实现的,因此,同样的考虑也适用于此。
注意,在 Win32 上情况可能完全不同:DLL 可能有其唯一的malloc
(当然还有free
)在自己的堆上运行。此类 DLL 中的内存 malloc
'd 必须在同一个 DLL 中为 free
'd。
【讨论】:
在 linux 上实际程序和它调用的 *.so 将共享相同的程序空间对吗?我的意思是,如果我从 *.so 调用new
并从主程序调用 delete
以获得相同的指针,它会工作吗?
可以,只要您不依赖多态行为的 C++ 本机实现(包括虚拟析构函数)。正如其他人已经指出的那样,多态类型的对象将包含一个指向虚函数表的幕后指针。类的 VFT 带有定义该类的构造函数的模块;因此它会在模块卸载时被卸载,然后所有的虚拟调用都会导致你的程序崩溃。以上是关于在动态加载的库中,我的内存分配在哪里?的主要内容,如果未能解决你的问题,请参考以下文章