如何解决内存分段并强制FastMM向OS释放内存?

 NarratorWang 发布于 2023-02-09 13:05

注意:32位应用程序,不计划迁移到64位.

我正在使用一个非常耗费内存的应用程序,并且几乎已经针对内存分配/解除分配优化了所有相关路径.(没有内存泄漏,没有句柄泄漏,应用程序本身没有任何其他类型的泄漏AFAIK并且经过测试.我无法触及的第三方库当然是候选者,但在我的场景中不太可能)

该应用程序将经常分配单个和多维记录的单个和二维动态数组,最多4个单一.我的意思是5000x5000的记录(单,单,单,单)是正常的.在给定时间内甚至还有6或7个这样的阵列工作.这是必需的,因为在这些阵列上进行了大量的交叉计算,并且从磁盘读取它们将是真正的性能杀手.

有了这个澄清之后,由于这些大型动态数组在释放它们后不会消失,无论我将它们设置为0还是最终确定它们,我都会出现内存错误.这当然是FastMM为了快速而做的事情,我知道的很多.

我正在使用以下方法跟踪FastMM分配的块和处理消耗的内存(RAM + PF):

function CurrentProcessMemory(AWaitForConsistentRead:boolean): Cardinal;
var
  MemCounters: TProcessMemoryCounters;
  LastRead:Cardinal;
  maxCnt:integer;
begin
  result := 0;// stupid D2010 compiler warning
  maxCnt := 0;
  repeat
    Inc(maxCnt);
    // this is a stabilization loop;
    // in tight loops, the system doesn't get
    // much chance to release allocated resources, which in turn will get falsely
    // reported by this function as still being used, resulting in a false-positive
    // memory leak report in the application.
    // so we do a tight loop here, waiting, until the application reported memory
    // gets stable.
    LastRead := result;
    MemCounters.cb := SizeOf(MemCounters);
    if GetProcessMemoryInfo(GetCurrentProcess,
        @MemCounters,
        SizeOf(MemCounters)) then
      Result := MemCounters.WorkingSetSize + MemCounters.PagefileUsage
    else
      RaiseLastOSError;
    if AWaitForConsistentRead and (LastRead <> 0) and (abs(LastRead - result)>1024) then
    begin
      sleep(60);
      application.processmessages;
    end;
  until (not AWaitForConsistentRead) or (abs(LastRead - result)<1024) or (maxCnt>1000);
  // 60 seconds wait is a bit too much
  // so if the system is that "unstable", let's just forget it.
end;

function CurrentFastMMMemory:Cardinal;
var mem:TMemoryManagerUsageSummary;
begin
  GetMemoryManagerUsageSummary(mem);
  result := mem.AllocatedBytes + mem.OverheadBytes;
end;

我在64位计算机上运行代码,在崩溃之前我的最高内存消耗大约是3.3 - 3.4 GB.之后,我在应用程序的任何位置获得与内存/资源相关的崩溃.花了我一些时间来介绍一些第三方库中埋藏的大型动态数据使用情况.

我克服这个问题的方法是,我通过重新启动自己并使用某些参数关闭来使应用程序从它停止的地方恢复.如果内存消耗是公平的并且当前操作完成,这都是好的和花花公子.

当前内存使用量为1GB且下一个要处理的操作需要处理2.5 GB或更多内存时,会出现一个大问题.我的当前代码在恢复之前将自身限制为1.5 GB内存的上限值,但在这种情况下,我必须将限制降低到1 GB以下,这基本上会使应用程序在每次操作后自行恢复,甚至不保证一切都会好的.

如果另一个操作将有更大的数据集要处理并且它将需要总共4GB或更多内存,该怎么办?

要注意的是,我不是在讨论内存中实际的4 GB,而是通过分配巨大的动态数组来消耗内存,一旦取消分配,操作系统就不会回来,因此它仍然将其视为已消耗,因此它会增加.

因此,我的下一个攻击点是强制fastmm释放所有(或至少部分)内存到操作系统.我专门针对这里庞大的动态数组.同样,这些都在第三方库中,所以重新编码并不是真正的顶级选项.修改fastmm代码并编写proc来释放内存变得更加容易和快捷.

我无法从FastMM切换为当前整个应用程序,并且一些第三方库在使用PushAllocationGroup时进行了大量编码,以便快速查找并查明任何内存泄漏.我知道我可以编写一个虚拟的FastMM单元来解决编译参考,但是如果没有这种快速和确定的泄漏检测,我将会离开.

总结:有什么方法可以强制FastMM向操作系统发布至少一些大块?(当然,确实存在,实际的问题是:是否有人写过它,如果有的话,心灵分享?)

谢谢

稍后编辑:

我很快就会提出一个小的相关测试应用程序.模拟一个似乎并不容易

撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有