2016-03-08 176 views
0

使用VirtualAlloc时,我可以(ab)使用以下属性来简化内存管理。如何(暂时)从VirtualAlloc释放内存?

除非/直到实际访问虚拟地址,否则不分配实际的物理页面。

我运行下面的代码来分配块。

type 
    PArrayMem = ^TArrayMem; //pointer 
    TArrayMem = packed record //as per documentation 
    RefCount: Integer; 
    Length: NativeInt; 
    Elements: Integer; 
    end; 

var 
    a: array of integer; //dynamic array, structure see above 

procedure TForm38.Button1Click(Sender: TObject); 
const 
    AllocSize = 1024 * 1024 * 1024; //1 GB 
var 
    ArrayMem: PArrayMem; 
begin 
    //SetLength(a, 1024*1024*1024); //1G x 8*16 
    ArrayMem:= VirtualAlloc(nil, AllocSize, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE); 
    ArrayMem.RefCount:= 1; 
    ArrayMem.Length:= AllocSize div SizeOf(Integer); 
    a:= @ArrayMem.Elements; //a:= AddressOf(elements) 
    a[1]:= 10;  //testing, works 
    a[0]:= 4; 
    a[500000]:= 56; //Works, autocommits, only adds a few k to the used memory 
    button1.Caption:= IntToStr(a[500000]); //displays '56' 
end; 

这一切都很好。如果我的结构增长到1,000,000个元素,一切正常。
然而,假设之后我的结构缩减回到1.000个元素。

如何释放RAM,以便在需要时自动提供魔法提交?

警告
大卫告诫我说:分配一个投入大量(巨大)连续的内存页进行了大量的成本。
因此,将数组拆分为更小的块并使用类/记录抽取内部元素可能更有优势。

+0

这是不是很清楚你想要什么发布,“记忆”是一个非常模糊的术语。你在谈论RAM还是地址空间? RAM是自动的,不需要帮助。如果你想释放地址空间,那么像这样使用VirtualAlloc()是个不错的主意,用HeapAlloc()代替。 –

+0

@HansPassant,对不起,我的意思是RAM。我并不担心地址空间,因为我只在Win64中运行。 – Johan

+0

你不能直接修改RAM分配,这是操作系统的工作。 SetProcessWorkingSetSize()是强制RAM页面的原始大锤,在这里肯定不合适。跟进@David,我不认为他明白你的意思。 –

回答

1

您可以使用VirtualFree传递MEM_DECOMMIT标志来解除页面。然后你可以使用VirtualAlloc再次提交。

或者您可以使用Windows 8.1中引入的DiscardVirtualMemory函数。

使用此功能可放弃不再需要的内存内容,同时保持内存区域本身的提交。丢弃内存可能会将物理RAM返回给系统。当应用程序再次访问内存区域时,后备RAM将被恢复,并且内存的内容不确定。

您可能会发现此相关的问题的东西在评论有用:New Windows 8.1 APIs for virtual memory management: `DiscardVirtualMemory()` vs `VirtualAlloc()` and `MEM_RESET` and `MEM_RESET_UNDO`

+0

我也可以做一个部分解除停止 - 重新提交吗?例如。我只想解除5.000以上的元素并重新提交给自动提交池。代码会像这样工作:'virtualfree(@a [5001],Size,MEM_DECOMMIT); VirtualAlloc(@a [5001],size,....)' – Johan

+0

据我了解,你可以这样做。我宁愿怀疑你可能会过度考虑问题。 –

+0

你是否建议我不打扰'VirtualFree'并让内存不再被使用? – Johan