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

发布于 2024-10-08 08:34:51 字数 918 浏览 1 评论 0原文

在最近的一篇文章中(我的程序永远不会释放内存。为什么?< /a> ) 我表明,当使用 FastMM 时,应用程序不会将大量内存释放回系统。 最近,我创建了一个人工测试程序,以确保问题不是内存问题,并且仅在 FastMM 中出现。

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

内存要求为(“私有工作集”):

没有 FastMM
运行循环之前:1.2MB
运行循环后:2.1MB

使用 FastMM(积极调试模式)
运行循环之前:2.1MB
运行循环后:25MB

使用 FastMM(释放模式)
运行循环之前:1.8MB
运行循环后:3MB

如果我运行循环多次,内存需求不会增加。这意味着未释放的内存被重新使用,因此这不是内存泄漏(内存泄漏会在每次运行时增加几 KB/MB 的内存占用)。


我的问题是:

如何在 FastMM 中禁用此行为?有可能吗?我知道,如果我在没有 FastMM 或使用 FastMM 发布模式的情况下发布程序,它将“浪费”适量的 RAM。但是按需禁用此行为将帮助我(我们?)识别内存泄漏。实际上,在我的第一篇文章(请参阅链接)中,很多人建议我有泄漏。显然正是因为这种行为才造成了混乱。不,很明显没有泄漏。只是内存管理器拒绝释放大量内存。

它会释放额外的内存吗?什么时候?是什么触发了这个?程序员可以触发吗?例如,当我知道我已经完成了一项 RAM 密集型任务,并且用户可能有一段时间不会使用该程序(最小化它)时,我可以将 RAM 刷新回系统吗?当用户打开我的程序的多个实例时会发生什么?他们不会争夺内存吗?

In a recent post ( My program never releases the memory back. Why? ) I show that when using FastMM, the application does not release substantial amounts of memory back to the system.
Recently I created an artificial test program to make sure the issue it is not a memory and that it only appears with FastMM.

In this program I create and destroy an object (same as the one used in the previous post) 500 times.

The memory requirements are ("Private working set"):

Without FastMM
Before running the loop: 1.2MB
After running the loop: 2.1MB

With FastMM (aggressive debug mode)
Before running the loop: 2.1MB
After running the loop: 25MB

With FastMM (release mode)
Before running the loop: 1.8MB
After running the loop: 3MB

If I run the loop several times, the memory requirement does not increase. Which means that the unreleased memory is re-used so this is not a memory leak (a memory leak would increase the memory footprint with several KB/MB at each run).


My questions are:

How can I disable this behavior in FastMM? Is it even possible? I know, if I release the program without FastMM or with FastMM Release Mode it will "waste" moderate amounts of RAM. But disabling this behavior on demand, will help me (us?) identifying memory leaks. Actually in my first post (see link) many people suggested that I have a leak. The confusion was created obviously just because of this behavior. No, it is obvious there is no leak. It is just the memory manager that refuses to release large amounts of memory.

It will ever release the extra memory? When? What triggers this? Can the programmer trigger it? For example when I know that I have finished a RAM-intensive task and the user may not use the program for a while (minimize it), can I flush the RAM back to the system? What happens when the user open multiple instances of my program? Won't they compete for RAM?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

病毒体 2024-10-15 08:34:51

实际上,您不应该将其视为“浪费”RAM。将其视为“缓存”未使用的 RAM。内存管理器出于某种原因保留未使用的内存而不是将其释放回操作系统,事实上您已经在问题中找到了这个原因。

您说您不断在循环中重新运行相同的操作。当您这样做时,它仍然具有可用的旧内存,并且可以立即分配它,而不必向 Windows 请求新的堆块。这是将“快速”置于“FastMM”中的技巧之一,如果不这样做,您会发现程序运行速度要慢得多。

您无需担心 FastMM 调试模式图。这仅用于调试,并且您不会发布针对 FullDebugMode 编译的程序。而“不使用 FastMM”和“使用 FastMM 发布模式”之间的差异约为 1 MB,这在现代硬件上可以忽略不计。只需额外增加 1 MB 的低成本,您就能获得巨大的性能提升。所以不用担心。

You shouldn't think about it as "wasting" RAM, really. Think about it as "caching" unused RAM. The memory manager is holding onto the unused memory instead of releasing it back to the OS for a reason, and in fact you've hit upon that reason in your question.

You said that you keep re-running the same operations in a loop. When you do that, it still has the old memory available and it can assign it immediately, instead of having to ask Windows for a new chunk of heap. This is one of the tricks that puts the "Fast" in "FastMM," and if it didn't do that you'd find your program running a lot more slowly.

You don't need to worry about the FastMM debug mode figure. That's only for debugging, and you're not going to release a program compiled against FullDebugMode. And the difference between "without FastMM" and "with FastMM Release Mode" is about 1 MB, which is negligible on modern hardware. For the low cost of only 1 extra MB, you get a big performance boost. So don't worry about it.

呆橘 2024-10-15 08:34:51

FastMM 快速的部分原因是它会分配大内存块并从中分割出较小的统一大小的块。如果块的任何部分正在使用,则任何部分都不能释放回操作系统。

欢迎您使用不同的内存管理器。一种方法是将所有分配直接路由到 VirtualAlloc< /a>.分配将被四舍五入以一次占据整个页面,因此如果您有大量小分配,您的程序可能会受到影响,但是当您调用 VirtualFree 时,您可以确信内存绝对不会'不再属于你的程序了。

另一种选择是将所有内容路由到操作系统堆。使用HeapAlloc。您甚至可以为您的程序启用低碎片堆(通过Windows Vista 中的默认设置),这将使操作系统采用与 FastMM 类似的策略,但它允许您使用 Microsoft 的一些调试和分析工具来跟踪程序随时间的内存使用情况。但请注意,在调用 HeapFree 后,某些指标可能仍将内存显示为属于您的程序。

此外,工作集是指当前物理RAM中的内存。您观察到数字上升并不意味着您的程序已经分配了更多内存。它可能只是意味着您的程序触及了它之前分配的一些内存,但尚未放入 RAM 中。在循环期间,您触及了该内存,并且操作系统尚未决定将其分页回磁盘。

Part of what makes FastMM fast is that it will allocate a large block of memory and carve smaller uniformly sized pieces out of it. If any part of the block is in use, none of it can be released back to the OS.

You're welcome to use a different memory manager. One approach would be to route all allocations directly to VirtualAlloc. Allocations will be rounded up to occupy an entire page at a time, so your program may suffer if you have lots of small allocations, but when you call VirtualFree, you can be confident that the memory definitely doesn't belong to your program anymore.

Another option is to route everything to the OS heap. Use HeapAlloc. You can even enable the low-fragmentation heap for your program (on by default as of Windows Vista), which will make the OS employ a strategy similar to the one used by FastMM, but it will allow you to use some debugging and analysis tools from Microsoft to track your program's memory usage over time. Beware, though, that after you call HeapFree, some metrics might still show the memory as belonging to your program.

Besides, the working set refers to the memory that's currently in physical RAM. That you observed the number go up does not mean that your program has allocated any more memory. It can simply mean that your program touched some memory that it had previously allocated, but which had not yet been put into RAM. During your loop, you touched that memory, and the OS has not decided to page it back out to disk yet.

莫相离 2024-10-15 08:34:51

我使用以下作为内存管理器。我这样做是因为它在线程争用情况下的性能比 FastMM 好得多,而 FastMM 实际上相当差。我知道像 Hoard 这样的可扩展管理器会更好,但这很适合我的需要。

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 相同。

I use the following as a memory manager. I do so because it performs much better under thread contention than FastMM which is actually rather poor. I know that a scalable manager such as Hoard would be better, but this is works fine for my needs.

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.

This isn't an answer to your question, but it's too long to fit into a comment and you may find it interesting to run your app against this MM. My guess is that it will perform the same way as FastMM.

偏爱自由 2024-10-15 08:34:51

已解决

根据 Barry Kelly 的建议,FastaMM 将自动释放内存。
为了证实这一点,我创建了第二个分配大量 RAM 的程序。一旦Windows耗尽RAM,我的程序内存利用率就恢复到原来的值。

问题解决了。
谢谢,巴里。

SOLVED

As suggested by Barry Kelly the memory will be released automatically by FastaMM.
To confirm this, I created a second program that allocated A LOT of RAM. As soon as Windows ran out of RAM, my program memory utilization returned to its original value.

Problem solved.
Thanks, Barry.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文