Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何说服内存管理器释放未使用的内存_Delphi_Fastmm - Fatal编程技术网

Delphi 如何说服内存管理器释放未使用的内存

Delphi 如何说服内存管理器释放未使用的内存,delphi,fastmm,Delphi,Fastmm,在最近的一篇文章()中,我展示了当使用FastMM时,应用程序不会将大量内存释放回系统。 最近,我创建了一个人工测试程序,以确保问题不是内存问题,并且它只在FastMM中出现 在这个程序中,我创建并销毁了一个对象(与前一篇文章中使用的对象相同)500次 内存要求为(“专用工作集”): 没有FastMM 运行循环前:1.2MB 运行循环后:2.1MB 使用FastMM(主动调试模式) 运行循环前:2.1MB 运行循环后:25MB 使用FastMM(释放模式) 运行循环前:1.8MB 运行循环后:3

在最近的一篇文章()中,我展示了当使用FastMM时,应用程序不会将大量内存释放回系统。 最近,我创建了一个人工测试程序,以确保问题不是内存问题,并且它只在FastMM中出现

在这个程序中,我创建并销毁了一个对象(与前一篇文章中使用的对象相同)500次

内存要求为(“专用工作集”):

没有FastMM
运行循环前: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的用户