2012-12-28 95 views
1

我正在处理一些有点奇怪的情况,但这正是我计划创建的。这只是一种特殊的测试软件...强制Windows释放分配的内存

我的环境:MSVS 2012,Windows 7/8 32b/64b。

所以,首先我创建了一些内部结构/缓存/等我的应用程序使用,那么我做这样的事情(在这里简化了一下,请把它有点像伪代码):

{ 
    std::deque<boost::scoped_array<unsigned char>> deque; 
    try { 
    while (1) { 
     deque.push_back(boost::scoped_array<unsigned char>(new unsigned char[system_page_size])); // happens to be 4096 on my system 
    } 
    } 
    catch (std::bad_alloc& ex) { ... } 
    // do something here 
} 

我需要使用尽可能多的内存。我一次分配整个页面(也许这很糟糕,应该为deque/smart ptr的数据留出一些空间?)。当CRT决定不再有可能进行分配时,我会做更多的事情(根本不依赖任何内存可用性),然后退出范围。它会触发一连串的析构函数,所有这些数据都应该被释放。

This works great。但是我碰巧进入这个奇怪的范围不是一次,而是循环中的10次。它有时会工作2到3次。有时只有一次。下次我只会得到内存不足的错误,就是这样。

从我的角度来看,我需要重新启动整个过程才能真正强制释放内存。有没有一种方法可以在单一过程中实现这一点?

我可以考虑尝试不同的分配器 - 也许这是CRT问题?我也玩过一些堆操作(即低碎片堆),但也没有帮助。

+0

你正在分割堆。这是正常的行为 - “窗户”不会为你留住记忆。你可以直接调用'VirtualAlloc'来完成这个工作。 –

+0

好吧,我分解过程堆,但然后我试图分配完全相同种类的块。在这里我没有看到问题,因为在第一个bad_alloc抛出后没有额外的分配。 – Mickey

回答

0

为什么不使用MEM_RESERVE调用一些大型调用VirtualAlloc调用来保留进程的整个内存空间。然后,您将在每个内存范围稍后调用VirtualFree进行发布。这仍然需要一些堆分配,就像你在这里所做的那样,以消耗当前堆的其余部分。它会更快,并删除您必须遇到的页面文件流失。

至于你的具体问题,我不知道你为什么遇到它。保留所有内存以便堆不能扩展应该有助于减少非确定性。

+0

是否有一个很好的方法来计算这几个大页面的大小?如果我会问太多,那就会失败。 – Mickey

+0

您可以通过调用[VirtualQuery](http://msdn.microsoft.com/en-us/library/aa366902%28v=vs)来映射进程的地址空间。85%29.aspx),直到你耗尽了你的地址空间。然后所有的MEM_FREE区域都可以使用VirtualAlloc保留。只需从最小地址开始查询,并将其长度扩展到最大地址。检查GetSystemInfo以获取寻址范围。 – Avilo

+0

如果这是多线程,我将添加,分配的页面将会更改,以便VirtualQuery报告空闲范围时立即保留该地址。保存结果指针以供稍后释放。您可能想要首先分配一个大型数组来保存这些指针,因为STL容器会动态地分配每个指针,这可能会因为内存耗尽而失败。 – Avilo

0

如果你使用大量的内存,使用某种slab分配(VirtualAlloc会为你提供内存),然后原则上[假设你创建的对象不需要析构函数做一些事情],你可以一次性扔掉整个块,而不是使用删除巨额代码 - 同时还可以节省时间以及保证你的内存已经完全释放。

我怀疑你可能有问题的一个原因是释放的块在被回收之前必须被清除。这是在内核的后台线程中完成的。当然,使用VirtualALloc实际上对此帐户无帮助。

当然你也可能会得到内存碎片,在这种情况下,使用一个旨在避免这种情况的头部会起作用。