多个进程或库副本之间的C字符串文字存储

当您运行特定程序或库的多个副本时,各种系统的行为是什么,字符串文字是在RAM中存储一次还是对于进程/库的每个副本存储一次? 如果它们存储在如下数组中,该怎么办?

static const char *const foo[] = { "bar", "baz", "buz" }; 

static是否会改变内存存储的行为?

编辑:由于它可能是特定于平台的,因此Windows上的Microsoft编译器或Linux上的GCC(x86)上的行为是什么?

假设您询问动态链接的库数据,通常每个进程都会获得自己的数据副本,至少是虚拟的。 但是,操作系统实际上可以使用相同的RAM来保存这些数据。 如果数据随后由其中一个进程写入,则操作系统将创建该进程可能更改的数据的新副本,并让其他进程继续查看旧副本。 这称为写入时复制(COW)。

对于静态链接库,程序通常有自己的数据副本,除非同一个程序运行多次,该程序的每个实例都可能以与动态链接相同的方式共享相同数据的视图图书馆数据。

有些操作系统可能没有实现COW的东西。

编辑

在阅读了另一篇文章的评论后,我决定再深入研究一下。

由于你有很多字符串文字,它们是常量,因此它们应放在可执行文件的只读部分。 由于它们是只读的,因此无论如何都会错误地尝试写入它们,因此操作系统可能不必复制它们。

如果你声明了很多字符串变量并且没有将它们声明为常量变量(oxymoron)那么你可能会得到更多的副本,因为它们会放在可执行文件的可写部分中,即使你没有写入他们可以写入与他们关系密切的其他数据,这可能会导致他们与该数据一起被复制。

我认为这是特定于平台的,因为该语言中没有这样的规范。

静态是否会改变内存存储的行为?

是,但不是关于进程或库的多个副本之间的字符串文字存储。

由于进程的内存是隔离的(大多数情况下),每个进程都有一个虚拟内存中所有字符串的副本。 但这取决于编译器(我没有研究编译器如何处理各种字符串常量声明)。 通常,如果数据块(或代码)被映射到地址空间,则它不会“加载”到物理内存中而不是需要。 一个副本保存在物理内存块(页面)中,此页面映射到多个进程的不同虚拟地址。 如果修改一个进程的虚拟空间中的数据,则会创建此页面的副本并将其映射到旧虚拟地址。

在您的任务中,将所有资源保留为PE资源并将其加载到内存映射文件中是有意义的。 如果先前的应用程序实例尚未执行此操作, 每个应用程序实例都会执行此操作。 这样你在内存中只有一个常量副本。

static不应该影响这一点,因为它没有对字符串文字本身做出规范。 它们仍然可能从其他编译单元返回给调用者,从而返回到链接到库的应用程序,例如

Windows和我相信Unix / Linux, 允许这样,并且在早期,当RAM受限时,鼓励它使用。 然而,这是在节省内存和保留内存保护之间的权衡。 随着内存寻址范围的扩大,RAM变得便宜,很大程度上决定它不值得麻烦。 (在Win16中,我认为这样做是默认的;在Win32下,它需要一些手动步骤来使用它)

在某些特殊环境(例如嵌入式系统)中,它可能仍然值得(但嵌入式系统很少需要运行同一应用程序的两个副本)

更新:在Windows中,您可以拥有一个仅限资源的DLL,可以将其标记为“共享”。 这可能是处理你想要的最好方法。