问题 共享库的内存空间


C ++共享库是否有自己的内存空间?或者它共享呼叫者进程'一个?

我有一个共享库,其中包含一些类和包装函数。 其中一个包装函数有点:

libXXX_construct() 初始化一个对象并返回指向所述对象的指针。

一旦我使用 libXXX_construct() 在调用者程序中放置的对象是什么?它是在“调用者”内存空间中还是在库的内存空间中?


2839
2017-07-24 14:39


起源



答案:


共享库的链接实例直接或间接共享链接到它的可执行文件实例的内存空间。对于Windows和类似UN * X的操作系统都是如此。请注意,这意味着共享库中的静态变量不是进程间通信的方式(很多人都认为)。


7
2017-07-24 14:45



如果链接到共享库的可执行文件也是共享库怎么办?在内部.so中创建的对象是在main的相同内存空间中(调用后者.so) - nick2k3
只有一个内存空间。
默认情况下为True,但为静态变量 能够 用于在Windows上共享数据。详情请见我的回答。 - MSalters
嗯,他们肯定是一个不良的进程间机制:-)
为什么有人会这么想的!现在开发人员不要基本掌握操作系统为他们做的事情! - Martin York


答案:


共享库的链接实例直接或间接共享链接到它的可执行文件实例的内存空间。对于Windows和类似UN * X的操作系统都是如此。请注意,这意味着共享库中的静态变量不是进程间通信的方式(很多人都认为)。


7
2017-07-24 14:45



如果链接到共享库的可执行文件也是共享库怎么办?在内部.so中创建的对象是在main的相同内存空间中(调用后者.so) - nick2k3
只有一个内存空间。
默认情况下为True,但为静态变量 能够 用于在Windows上共享数据。详情请见我的回答。 - MSalters
嗯,他们肯定是一个不良的进程间机制:-)
为什么有人会这么想的!现在开发人员不要基本掌握操作系统为他们做的事情! - Martin York


所有共享库共享其虚拟内存空间 处理。 (包括主要的可执行文件本身)


2
2017-07-24 14:41





除非另有说明, 共享库将与托管它的进程共享内存。然后,每个流程实例都有自己的副本。

但是,在Windows上,可以创建允许进程间通信的共享变量。您可以将它们放在正确的段中。默认情况下,Windows使用两种段:数据段是读/写非共享的,而代码段是只读的可执行和共享。但是,读写和共享属性是正交的。库中的共享读写段可用于存储共享变量,它将一直存在,直到最后一个进程退出。

小心C ++,因为即使你把变量放在共享段中,它也会在进程启动和退出时愉快地运行构造函数和析构函数。

有关详情,请参阅 PE内部对等:Win32可移植可执行文件格式之旅第2部分 作者:Matt Pietrek。


2
2017-07-24 15:15



这超出了C ++的范围(你正在考虑摆弄程序集)。有充分的理由不这样做(特别是为什么它们不包括在语言结构中)。使用操作系统提供进程间通信功能。它是安全的东西。 - Martin York
问题所在的共享库超出了C ++的范围,IPC也是如此。 C ++只有外部或内部链接,它没有同时运行多个程序的概念,除了可以说与信号有关。 - Steve Jessop
@Martin York:嗯,如果你想要了解一个现有的程序(并且可以阅读这个问题的建议),你必须面对前一个作者确实这样做的可能性。你错误的原因是它们没有被包含在语言中 - 这是因为这些技巧本质上是特定于平台的,而ISO C ++则不是。 - MSalters


共享库与其主机进程具有相同的地址空间。它必须是这样的,否则你将无法将指针从一个模块传递到另一个模块,因为它们无法取消引用它们。

但是虽然它们位于相同的地址空间,但这并不意味着它们都使用相同的内存管理器。结果是,如果你提供一个代表调用者分配内存的函数,那么你应该提供一个相应的函数来释放那个内存,比方说, libXXX_destroy()


1
2017-07-24 14:55



你能解释一下这个内存管理器的东西吗? - nick2k3
当您执行malloc()或现在的操作时,内存管理器似乎会为您动态分配内存。这与库地址空间问题只有几乎相关,因为您可以在同一个.c或.cpp源文件中使用不同的管理器,这与不同的库完全不同。
@Neil。我认为作者是指每个DLL静态链接到运行时库时的问题。这导致每个DLL基本上都执行自己的内存管理(因此一个DLL无法释放由另一个DLL分配的内存)。尽管使用了运行时库的共享DLL,但这个问题已经很久了。 - Martin York
@martin我只是试图化解可能的红鲱鱼。基本问题是关于内存空间,而不是特定语言的内存分配。
是的,Neil,没有共享库就可能出现这个问题,但是还有更多的潜力 同 他们。马丁,问题是可以解决的,但这与解决的不一样。它们可能链接到不同的版本,或者它们可能链接到不同供应商的运行时。图书馆消费者可能使用完全不同的语言,无法打电话 delete。最后,Neil,它可能超出了最初的问题,但我认为在这种情况下仍然值得一提,因为记住拥有相同的地址空间并不意味着拥有相同的内存池是很重要的。 - Rob Kennedy


您的对象存在于调用者的内存空间中(实际上是库和主可执行文件之间共享的一个内存空间)


0
2017-07-24 14:43





共享地址空间,以便您可以共享指针,但是它们不共享分配器(至少不在Windows上)。

这意味着如果您调用new来在共享库中分配对象,则必须在同一个库中调用delete,否则可能会发生奇怪的事情。


0
2017-07-24 14:44



那个问题已经解决了。这对于Windows上的旧版开发来说是正确的,现代开发它不再是有效的问题。只需确保将所有DLL链接到运行时的共享版本。 - Martin York
谢谢,我不知道已经改变了。我最近遇到的问题很可能是静态运行时库的两个实例,它们在可执行文件和dll之间没有共享。 - Laserallan


确实,库会在每个加载内存的进程中耗尽内存。但是,至少在Windows下,当多个进程加载相同的DLL时,未修改的页面(包括所有代码页)将被隐藏在窗口下。此外,它们在交换文件中不占用空间,因为它们由原始文件支持。

我认为由于JIT编译,这对于.NET来说更复杂,但对于NGENed程序集仍然如此。

编辑

这是VM的细节。但是,你也可以  DLL中要在进程间共享的段。


0
2017-07-24 15:55