Win32可以“移动”堆分配的内存吗?

时间:2010-01-19 20:41:55

标签: c++ windows winapi memory-management heap

我有一个.NET /本机C ++应用程序。目前,C ++代码在默认堆上分配内存,该内存在应用程序的生命周期中持续存在。基本上,函数/命令在C ++中执行,这导致当前持久性存储器的分配/修改。我正在研究一种在执行中取消其中一个功能/命令的方法。我们有数百个这样的命令,而且很多都是非常复杂的(遗留)代码。

我试图避免的暴力方法是修改每个命令/函数以检查取消并进行所有适当的清理(释放堆内存)。我正在研究一种多线程方法,其中一个额外的线程接收取消请求并终止命令执行线程。我希望使用HeapCreate()(Win32)在“私有堆”上分配所有动态内存。这样,处理取消请求的线程可能会破坏私有堆。但是,如果命令运行完成,我需要动态内存来保持。在这种情况下,我想做的逻辑等效于将私有堆内存“移动”到默认/进程堆而不会产生实际副本的成本。这有可能吗?这甚至有意义吗?

或者,我认识到我可以为每个命令/函数执行一个新的私有堆(每个都是一个新线程)。如果命令被取消,则可以销毁私有堆,或者如果命令完成,它将存在。无限期增长的数量是否存在任何问题?我知道每个堆都有一些开销。我可能遇到什么限制?

我运行的是Windows 7 64位,内存为8GB(认为这是目标平台)。我正在使用的应用程序大约是100万SLOC(一半C ++,一半C#)。我正在寻找有关私有堆管理的任何经验/建议,或者只是我解决方案的替代方案。

4 个答案:

答案 0 :(得分:4)

使用单独的进程而不是单独的线程可能会更好:

  • 使用内存映射文件(即根本不是文件 - 只是交叉处理的共享内存)
  • 杀死进程比杀死线程更“干净”
  • 你可以让共享内存“幸存”而无需移动 - 你映射/取消映射而不是移动

虽然您可能需要自己进行一些内存管理。

无论如何,值得研究。我正在考虑使用进程间内存来处理其他一些事情,并且它有一些不寻常的属性(可以清楚地回忆所有这些,它是在不久之前),并且你可能能够利用它。

只是一个想法!

答案 1 :(得分:2)

从MSDN的Heap Functions页面: “由HeapAlloc分配的内存不可移动.HapAlloc返回的地址有效,直到内存块被释放或重新分配;内存块不需要被锁定。”

您可以将遗留应用程序与您自己的malloc()实现重新链接吗?如果是这样,您应该能够在不修改其余代码的情况下进行管理。您的自定义malloc库可以按线程跟踪已分配的块,并具有一个“FreeAllByThreadId()函数,您可以在杀死遗留函数的线程后调用它。您可以在库中使用私有堆。

私有堆的替代方法可能是从内存映射文件中进行自己的分配。请参阅“Creating Named Shared Memory”。在为旧线程初始化alloc库时创建共享内存。成功后,将其映射到主线程,以便c#可以访问它;在终止时,关闭它并将其释放到系统中。

答案 2 :(得分:1)

没有。内存不能在堆之间移动。

答案 3 :(得分:1)

堆是一大块记忆。它是用户级内存管理器。堆由较低级别的系统内存调用创建(例如,Linux中的sbrk和Windows中的VirtualAlloc。在堆中,然后您可以通过malloc / new / free / delete请求或返回一小块内存。默认情况下,进程具有单个堆(与堆栈不同,所有线程共享堆)。但是,你可以有很多堆。

  • 是否可以组合两个没有复制的堆?堆本质上是一个数据结构,它维护已使用和已释放的内存块列表。因此,堆应该有一种称为元数据的簿记数据。当然,这个元数据是每堆。 AFAIK,没有堆管理器支持两个堆的合并操作。我已经在Linux glibc(Doug Lea's implementation)中查看了malloc实现的完整源代码,但没有这样的操作。 Windows堆*功能也以类似的方式实现。 因此,目前无法移动或合并两个单独的堆。

  • 是否有可能有很多堆?我不认为有很多堆应该是一个大问题。正如我之前所说,堆只是一个保持已使用/释放内存块的数据结构。所以,应该有一些开销。但是,情况并不严重。当您查看malloc implementation之一时,会有malloc_state,这是每个堆的基本数据结构。例如,您可以通过create_mspace创建另一个堆(在Windows中,它是HeapCreate),然后您将获得一个新的malloc状态。它不是那么大。所以,如果这个踩踏(一些堆开销与实现容易度)很好,那么你可以继续。

如果我是你,我会尝试你描述的方式。对于我,这说得通。拥有大量堆对象不会产生很大的开销。

此外,应该注意,技术上移动的存储区域是不可能的。指向移动的内存区域的指针将导致悬空指针。

P.S。您的问题似乎是一个事务,尤其是软件事务内存。 STM的典型实现缓冲挂起的内存写入,然后提交到实际系统内存,事务没有冲突。