【问题标题】:C++ Reserve Memory SpaceC++ 保留内存空间
【发布时间】:2011-01-30 09:06:11
【问题描述】:

有什么方法可以保留默认的 Windows 内存管理器稍后使用的内存空间,这样如果我的程序使用的空间不超过我在程序启动时保留的空间,我的应用程序就不会耗尽内存?

【问题讨论】:

  • 请注意它所说的部分:“当应用程序需要更多堆空间时,更高的提交值可以节省时间,但会增加内存需求,可能还会增加启动时间。”
  • @paul:所以通过设置更高的值,我可以提高运行速度但降低启动速度+增加内存需求?
  • 如果您提前知道您将要进行一些大分配,那么这可能在您进行这些分配时为您节省一点时间,但是会有其他惩罚,您的整体应用程序性能可能没有什么不同。我的猜测是不值得,但还是继续尝试吧,因为它非常简单。
  • 为什么要这样做?我能想到的唯一方法是在程序启动时分配那么多内存并实现自己的新/删除运算符来管理它,而不是使用操作系统堆。

标签: c++ windows optimization memory


【解决方案1】:

当你有虚拟内存时,做这种事情是没有意义的。

【讨论】:

  • 我只是想做一些优化,虚拟内存很慢,因为它涉及磁盘读/写
  • @uray:Paul 的观点是,虚拟内存系统不会告诉你什么时候内存满了,是时候开始使用“reserve”,而是让你保留“reserve”并开始分页。这会导致您试图避免的“使用慢速基于磁盘的内存”的情况。
  • 顺便说一句——这与不那么复杂的内存系统(例如 Mac System 6 使用的内存系统)形成鲜明对比,在 Mac System 6 中,提前获取保留的内存块,以便您可以在第一次分配时释放它回来时“内存不可用”让你继续(尽管优雅地失败更安全)。
  • @Paul R:也许你还可以回答后续问题,“是否可以保留并提交内存”?当然,虚拟内存基于一个不正确的前提留下了问题,即为程序“保留”内存是可能的。但是 JB 描述了一个有效的问题,这很可能是这个提问者的问题,或者是将来通过搜索找到这个问题的人的问题。如果有人不明白虚拟内存会使进程“保留”空间变得毫无意义,他们也不会知道找到合适答案的神奇词是“提交”。
  • “毫无疑问它在某处被使用过”。 Windows 将其称为提交,例如 VirtualAlloc 的 MEM_COMMIT 参数。那是用 something 支持虚拟地址范围,不一定是物理 RAM。可能只是交换/页面文件。但是我看到你已经从提问者那里取笑了,意图是某种模糊的性能改进,所以在这种情况下,我认为你是对的,没有意义。如果 JB 希望他的建议被认为是另一个问题:-)
【解决方案2】:

虽然这通常是一个非常糟糕的主意(正如其他人已经指出的那样),但 Windows 确实允许这样做。如果您真的坚持,请查看VirtualLock。至少在 99% 的情况下,这是错误的做法,但总是可能(尽管极不可能)你正在做的事情属于证明它合理的事情的一小部分.

【讨论】:

  • 这如何回答这个问题? VirtualLock() 只是防止内存页面被换出到磁盘。它不保留任何内存。不管页面是否被锁定,进程可用的虚拟内存量保持不变。 VirtualLock() 主要用于安全和实时相关用例,以防止潜在的敏感数据被写入磁盘,并可能分别提高运行时的确定性。
  • @Void:在您的评论中,您写道:“VirtualLock() 只是防止内存页面被换出到磁盘。它不保留任何内存。” ——这个说法是不正确的。函数VirtualLock 确实保留了物理 内存。如果虚拟内存页面尚未由物理内存支持,那么它们将由物理内存支持,直到调用VirtualUnlock。您是对的,该功能不保留虚拟内存。这必须通过其他方式完成,例如使用函数VirtualAlloc
【解决方案3】:

在任何给定时刻,您的应用程序都不一定有任何物理内存。

如果您的应用正在等待 IO 操作一段时间并且用户开始编辑视频,则您的应用可能会完全从物理内存中消失。它只存在于页面文件中。当 IO 操作完成并且您的一个线程需要重新开始运行时,您将获得一些物理内存。

您真正可以分配的只是进程地址空间的一部分。它的一部分可能被映射到文件(例如您的 EXE 或任何不需要重新定位的本机 DLL)。其他部分可能是“内存分配”,但实际上这只是意味着它们被映射到页面文件中的位置。

在任何可靠的意义上,这些都不是“真正的”记忆。

您肯定会用尽地址空间中的空间。如果您多次分配 100MB 块,再加上一些较小的块,那么很快您就会对地址空间进行分段(默认情况下,它只为您提供足够的空间来容纳大约 20 个这样的块,并且任何给定的块都必须适合一个连续的区域)。

【讨论】:

    【解决方案4】:

    不是隐含的。没有办法告诉 C 内存管理器(当您调用 mallocnew 时,它会为您提供内存)保留空间。

    您可以做的是使用自己的专用分配器或缓冲池并手动管理分配和内存预留。


    编辑 -
    在 Windows 上,您可以使用 VirtualAllocExVirtualFreeEx 要求 Windows 为您保留内存页。但是没有办法告诉mallocnew 使用这个内存。如果您选择走这条路,则需要实现自己的内存管理器。

    【讨论】:

    • 我并没有严格要求 C 内存管理器,有没有 Win32/64 可以这样做?
    【解决方案5】:

    这甚至不是远程可移植的,但在许多系统中,当你释放它时,你分配的内存不会返回给操作系统,它只是放回该程序的空闲列表中。

    因此,如果您在程序启动时分配一个足够大的块,然后立即释放它,那么从那时起,该内存将可供内存分配器在该程序中分配。

    您当然必须确保您的平台以这种方式运行。最好的情况是它不便携,但最坏的情况应该不会伤害任何东西。

    【讨论】:

    • 感谢您的建议,在这种情况下我不在乎便携性。
    • 这更有可能在虚拟机操作系统中产生相反的效果。您只会浪费页表条目和 TLB 条目,并且您将更快地开始分页。整个预分配的想法是严重的old skool - 从 PC 操作系统没有 VM 的日子开始,只有一个有限的物理内存池,在所有进程之间共享。
    • 嗯? VM 并不神奇,任何类型的可用内存资源仍然是有限的。如果您将一些资源预先分配给特定进程,那么您知道稍后您将拥有该进程所需的内存。是的,当然它可能会导致额外的分页,但这是在任何系统上保留一些内存的成本。除非标准库将分配的内存释放回操作系统,否则我看不出这是如何工作的
    猜你喜欢
    • 2016-04-20
    • 2019-08-13
    • 2021-06-05
    • 2023-03-16
    • 1970-01-01
    • 2017-05-27
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多