【问题标题】:How to (temporary) release memory from VirtualAlloc?如何(临时)从 VirtualAlloc 释放内存?
【发布时间】:2016-06-22 14:53:32
【问题描述】:

当使用VirtualAlloc 时,我可以(ab)使用以下属性来简化内存管理。

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

我运行以下代码来分配块。

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,以便在再次需要时自动提交?

警告
大卫警告我,分配一个提交的大(巨大)连续内存页面会带来很大的成本。
因此,将数组拆分为更小的块并使用类/记录抽象出内部可能更有利。

【问题讨论】:

  • 你想释放什么不是很清楚,“内存”是一个非常模糊的术语。您是在谈论 RAM 还是地址空间? RAM 是自动的,无需帮助。如果您想释放地址空间,那么像这样使用 VirtualAlloc() 是个坏主意,请改用 HeapAlloc()。
  • @HansPassant,对不起,我的意思是 RAM。我不担心地址空间,因为我只在 Win64 中运行。
  • 您不能直接修改 RAM 分配,这是操作系统的工作。 SetProcessWorkingSetSize() 是一个粗暴的大锤来强制 RAM 页面出来,在这里肯定不合适。跟进@David,我认为他不明白你的意思。
  • @HansPassant, ? SetProcessWorkingSetSize 来自哪里?我又在说VirtualAlloc+VirtualFree+VirtualAlloc了。
  • 您正在发送混合信号,我跟进了您的“对不起,我的意思是 RAM”评论。不知道你在做什么了,我最好别插手了。

标签: winapi virtualalloc


【解决方案1】:

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

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

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

您可能会在相关问题的 cmets 中找到有用的信息:New Windows 8.1 APIs for virtual memory management: `DiscardVirtualMemory()` vs `VirtualAlloc()` and `MEM_RESET` and `MEM_RESET_UNDO`

【讨论】:

  • 我也可以进行部分解除提交-重新提交吗?例如。我只想取消提交高于 5.000 的元素并将其重新提交到自动提交池。像这样工作的代码:virtualfree(@a[5001],Size,MEM_DECOMMIT); VirtualAlloc(@a[5001], size,....)
  • 据我了解,您可以这样做。我宁愿怀疑你可能是在想这个问题。
  • 您是否建议我不要打扰VirtualFree,而让不再使用的内存保持提交状态?
  • 我想我可能会尝试在不直接调用虚拟内存 API 的情况下解决问题。
  • 我试过了,但是使用带有 4 GB 数据的 SetLength 会破坏系统并锁定 PC :-) 当我增长一个普通的 dynarray 时,我负担不起move 的成本使用设置长度。该应用程序使用记忆来加速一个过程,因此内存饥饿。一旦找到解决方案,我就可以释放内存。
猜你喜欢
  • 2011-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-13
  • 1970-01-01
  • 1970-01-01
  • 2011-01-31
相关资源
最近更新 更多