代码之家  ›  专栏  ›  技术社区  ›  thelsdj

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

  •  0
  • thelsdj  · 技术社区  · 16 年前

    当一个特定程序或库的多个副本运行时,不同系统的行为是什么?字符串文本是存储在RAM中一次,还是存储在进程/库的每个副本中一次?如果它们存储在一个数组中,比如:

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

    是吗? static 是否更改内存存储的行为?

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

    5 回复  |  直到 16 年前
        1
  •  2
  •   nategoose    16 年前

    假设您询问的是动态链接的库数据,通常每个进程都会得到自己的数据副本,至少实际上是这样。不过,操作系统实际上可以使用相同的RAM来保存这些数据。如果数据是由某个进程写入的,那么操作系统将生成该进程可能更改的数据的新副本,并让其他进程继续查看旧副本。这就是所谓的书面副本(COW)。

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

    有些OSE可能无法实现奶牛的功能。

    编辑

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

    由于您有很多字符串文本(它们是常量),所以它们应该放在可执行文件的只读部分中。因为它们是只读的,所以您的程序无论如何都会试图写入它们,这样操作系统就不必复制它们。

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

        2
  •  1
  •   Brian R. Bondy    16 年前

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

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

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

        3
  •  1
  •   Eugene Mayevski 'Callback    16 年前

    由于进程的内存是独立的(好吧,大多数情况下),每个进程都有其中所有字符串的副本 事实上的 记忆。但是,这取决于编译器(我没有研究编译器如何处理各种字符串常量声明)。一般来说,如果数据块(或代码)被映射到地址空间中,那么它不会“加载”到超出需要的物理内存中。一个副本保存在物理内存块(页)中,该页映射到多个进程的不同虚拟地址。如果修改一个进程的虚拟空间中的数据,则 复制 将创建此页的,并将其映射到旧的虚拟地址。

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

        4
  •  0
  •   Jens Gustedt    16 年前

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

        5
  •  -1
  •   James Curran    16 年前

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

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

    更新:在Windows中,可以有一个只包含资源的dll,它可以标记为“共享”。这可能是处理你想要的事情的最佳方法。