Delphi 如何说服内存管理器释放未使用的内存
在最近的一篇文章()中,我展示了当使用FastMM时,应用程序不会将大量内存释放回系统。 最近,我创建了一个人工测试程序,以确保问题不是内存问题,并且它只在FastMM中出现 在这个程序中,我创建并销毁了一个对象(与前一篇文章中使用的对象相同)500次 内存要求为(“专用工作集”): 没有FastMMDelphi 如何说服内存管理器释放未使用的内存,delphi,fastmm,Delphi,Fastmm,在最近的一篇文章()中,我展示了当使用FastMM时,应用程序不会将大量内存释放回系统。 最近,我创建了一个人工测试程序,以确保问题不是内存问题,并且它只在FastMM中出现 在这个程序中,我创建并销毁了一个对象(与前一篇文章中使用的对象相同)500次 内存要求为(“专用工作集”): 没有FastMM 运行循环前:1.2MB 运行循环后:2.1MB 使用FastMM(主动调试模式) 运行循环前:2.1MB 运行循环后:25MB 使用FastMM(释放模式) 运行循环前:1.8MB 运行循环后:3
运行循环前:1.2MB
运行循环后:2.1MB 使用FastMM(主动调试模式)
运行循环前:2.1MB
运行循环后:25MB 使用FastMM(释放模式)
运行循环前:1.8MB
运行循环后:3MB 如果我多次运行循环,内存需求不会增加。这意味着未释放的内存被重新使用,因此这不是内存泄漏(内存泄漏会在每次运行时增加几KB/MB的内存占用)
我的问题是: 如何在FastMM中禁用此行为?有可能吗?我知道,如果我在没有使用FastMM或使用FastMM发布模式的情况下发布程序,它将“浪费”适量的RAM。但在需要时禁用此行为将有助于我(我们?)识别内存泄漏。实际上,在我的第一篇帖子(见链接)中,很多人都认为我有漏洞。这种混乱显然就是因为这种行为造成的。不,很明显没有泄漏。只是内存管理器拒绝释放大量内存
它会释放额外的内存吗?什么时候是什么触发了这一切?程序员能触发它吗?例如,当我知道我已经完成了RAM密集型任务,并且用户可能有一段时间不使用该程序(将其最小化)时,我可以将RAM刷新回系统吗?当用户打开我的程序的多个实例时会发生什么?他们不会争夺内存吗?你不应该认为这是“浪费”内存,真的。将其视为“缓存”未使用的RAM。内存管理器保留未使用的内存,而不是出于某种原因将其释放回操作系统,事实上,您在问题中已经找到了这个原因 你说过你一直在循环中运行相同的操作。当您这样做时,它仍然有可用的旧内存,并且可以立即分配它,而不必向Windows请求新的堆块。这是将“Fast”放在“FastMM”中的技巧之一,如果不这样做,你会发现你的程序运行得慢得多
您不必担心FastMM调试模式图。这只是为了调试,您不会发布根据FullDebugMode编译的程序。“无FastMM”和“有FastMM释放模式”之间的差异约为1MB,在现代硬件上可以忽略不计。只需额外增加1 MB的低成本,就可以大大提高性能。所以别担心。让FastMM快速的部分原因是它将分配一大块内存,并从中雕刻出大小一致的小块。如果块的任何部分正在使用中,则不能将其释放回操作系统 欢迎您使用不同的内存管理器。一种方法是将所有分配直接发送到。分配将一次四舍五入以占据整个页面,因此如果您有大量小的分配,您的程序可能会受到影响,但是当您调用
VirtualFree
时,您可以确信内存肯定不再属于您的程序
另一种选择是将所有内容路由到操作系统堆。使用。您甚至可以为您的程序启用(在Windows Vista中默认为打开),这将使操作系统采用与FastMM使用的策略类似的策略,但它允许您使用Microsoft提供的一些调试和分析工具来跟踪您的程序随时间的内存使用情况。不过,请注意,在调用HeapFree
之后,某些指标可能仍会显示内存属于您的程序
此外,工作集指的是当前在物理RAM中的内存。你观察到数字上升并不意味着你的程序已经分配了更多的内存。它可以简单地表示,您的程序触及了它以前分配的一些内存,但这些内存尚未放入RAM。在循环过程中,您触及了该内存,操作系统尚未决定将其分页回磁盘。我将以下内容用作内存管理器。我这样做是因为它在线程争用下的性能比FastMM好得多,而FastMM实际上相当差。我知道像这样一个可扩展的管理器会更好,但这适合我的需要
unit msvcrtMM;
interface
implementation
type
size_t = Cardinal;
const
msvcrtDLL = 'msvcrt.dll';
function malloc(Size: size_t): Pointer; cdecl; external msvcrtDLL;
function realloc(P: Pointer; Size: size_t): Pointer; cdecl; external msvcrtDLL;
procedure free(P: Pointer); cdecl; external msvcrtDLL;
function GetMem(Size: Integer): Pointer;
begin
Result := malloc(size);
end;
function FreeMem(P: Pointer): Integer;
begin
free(P);
Result := 0;
end;
function ReallocMem(P: Pointer; Size: Integer): Pointer;
begin
Result := realloc(P, Size);
end;
function AllocMem(Size: Cardinal): Pointer;
begin
Result := GetMem(Size);
if Assigned(Result) then begin
FillChar(Result^, Size, 0);
end;
end;
function RegisterUnregisterExpectedMemoryLeak(P: Pointer): Boolean;
begin
Result := False;
end;
const
MemoryManager: TMemoryManagerEx = (
GetMem: GetMem;
FreeMem: FreeMem;
ReallocMem: ReallocMem;
AllocMem: AllocMem;
RegisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak;
UnregisterExpectedMemoryLeak: RegisterUnregisterExpectedMemoryLeak
);
initialization
SetMemoryManager(MemoryManager);
end.
这不是对你问题的回答,但它太长,无法放在评论中,你可能会发现针对这个MM运行你的应用程序很有趣。我的猜测是,它将以与FastMM相同的方式执行。已解决 正如Barry Kelly所建议的,FastaMM将自动释放内存。 为了确认这一点,我编写了第二个程序,分配了大量RAM。Windows的RAM一用完,我的程序内存利用率就恢复到原来的值 问题解决了。
谢谢你,巴里。你好,梅森。“…保留未使用的内存,而不是出于某种原因将其释放回操作系统”--上帝!我不是在争论缓存的好处!!!缓存很好,我知道!但我想对它进行一些控制——至少出于调试目的。知道你的应用程序需要的内存的确切数量不是件好事吗?:)“只需额外增加1 MB的低成本,您就可以获得巨大的性能提升”--这就是我每次创建/销毁一个对象(500次)时“浪费”的RAM量。但是,如果我加载500个对象,然后将它们全部释放,那么未释放的RAM(由FastMM提供)的数量是相当可观的!Borland的内存管理器立即返回大部分内存!具有1 GB RAM EEA的用户