Delphi 查找最大的可用内存块

Delphi 查找最大的可用内存块,delphi,memory-management,Delphi,Memory Management,当它变得碎片化时,有时会出现内存不足的问题 有可能找到最大的空闲内存块吗? 我使用Delphi2007和FastMM。在Windows XP上开发Windows 2003上运行的应用程序 问候 编辑: 我可以添加应用程序在Windows server 2003 x64上具有32 GB内存的服务器上运行的信息。但该应用程序是32位应用程序,因此理论上每个实例的最大分配内存为2GB。多个实例同时运行。我不认为总的物理内存太少。我猜当应用程序启动时,会有一个32位的虚拟内存空间。在运行时,这可能会变得

当它变得碎片化时,有时会出现内存不足的问题

有可能找到最大的空闲内存块吗? 我使用Delphi2007和FastMM。在Windows XP上开发Windows 2003上运行的应用程序

问候

编辑: 我可以添加应用程序在Windows server 2003 x64上具有32 GB内存的服务器上运行的信息。但该应用程序是32位应用程序,因此理论上每个实例的最大分配内存为2GB。多个实例同时运行。我不认为总的物理内存太少。我猜当应用程序启动时,会有一个32位的虚拟内存空间。在运行时,这可能会变得过于零碎

我还找到了FastGetHeapStatus方法,该方法返回一个带有一些字段的THeapStatus,用于释放内存。也许我可以用这些

EDIT2: 我找到了这个。 代码是C,但可能可以翻译成Delphi。

不,这是旧Turbo Pascal中的“maxavail”,这是一个经常被请求的特性,但不幸的是,在多用户、多任务环境中,这是一个无用的概念

heapmanager可以知道它自己维护的内存中最大的块,但通常是小的,因为大的块直接从windows分配(并返回到windows)

而逐步尝试分配更大数据块的方案将失败,因为操作系统将授予请求,即使这意味着要用磁盘交换请求(这是您不想要的)。对于尝试通过windows api调用挖掘此类值的技巧也是如此

整个受保护模式环境的基础是共享内存,每个应用程序只使用所需的内存。忽视这一点,假装一切都像在Dos下一样,只会让同时运行多个应用程序的人产生大量抱怨

如果您的应用程序确实依赖于此,请使用安全(小)默认值将其设置为配置设置(启动时为某个对象分配多少内存)。如果这真的很重要,请在安装过程中与用户对质


当然,通过执行一些winapi调用并假设没有其他应用程序运行,可以始终使用启发式尝试来播种默认值。但最终决定权总是留给用户,特别是对于服务器应用程序。

在虚拟内存系统上,虚拟地址空间意味着虚拟页面可以映射到任何地方。您不需要大的连续物理内存块。如果您的虚拟地址空间存在碎片问题,那么您可能需要不同的内存管理策略

但是,大多数选项都要求应用程序代码在某种程度上了解内存管理策略。我不相信有一个快速修复这个问题-你可能是合理的大手术来修复它。这些选项都不容易实现,您必须找到最适合您的特定情况的选项

我可以看到的主要选项有:自定义内存分配器、涉及AWE的东西(见下文)或在应用程序中重建内存分配策略

选项1:自定义内存分配器

<>自定义内存分配器在C和C++循环中并不少见。您可能能够实现类似的功能。您有两种可能:

  • 构建一个内存分配器,其机制是尝试将相邻的空闲块合并为单个较大的块(您可以将此作为尝试从失败的内存分配中恢复的一部分来运行)。这可能允许您透明地管理内存,而无需应用程序知道。实现这一点需要技巧和技术,但可能是可行的。

    这种方法的主要好处是,它是唯一不需要您更改现有应用程序代码的方法。缺点是它不能保证有效;合并操作仍然可能无法整合足够大的内存块以满足请求。合并操作还可能导致运行时应用程序响应出现明显暂停

  • 您可能需要以允许压缩数据结构的方式构建应用程序。这需要您维护支持移动对象的句柄,即双间接机制。我猜可能有一个或相当少的不同数据结构导致了这个碎片化问题,因此有可能在应用程序中本地化任何重新架构的工作

选项2:PAE

Windows确实支持直接操作MMU的工具,这有几种可能适用于您的应用程序。这当然需要应用程序提供明确的体系结构支持,但可以使用比2GB大得多的内存池

在Windows的服务器版本上,查看,这是由支持的,允许您手动操作系统的MMU并重新映射内存块。这可能在两个方面对您有所帮助

  • 您可以使用此机制作为管理数据的固有部分,为数据结构构建管理器

  • 如果可以将数据结构中的项目与页面边界相匹配,则可以将其用作整合内存的方法

但是,这种方法需要您重新设计应用程序,以便对象引用具有足够的信息来管理显式的交换过程(可能是某种覆盖管理器,带有通过此系统引用的对象的代理机制)。这意味着任何涉及PAE的解决方案都不是FastMM的替代品-您必须修改应用程序以明确支持PAE

然而,这种代理机制可能意味着
function GetLargestFreeMemRegion(var AAddressOfLargest: pointer): LongWord;
var
  Si: TSystemInfo;
  P, dwRet: LongWord;
  Mbi: TMemoryBasicInformation;
begin
  Result := 0;
  AAddressOfLargest := nil;
  GetSystemInfo(Si);
  P := 0;
  while P < LongWord(Si.lpMaximumApplicationAddress) do begin
    dwRet := VirtualQuery(pointer(P), Mbi, SizeOf(Mbi));
    if (dwRet > 0) and (Mbi.State and MEM_FREE <> 0) then begin
      if Result < Mbi.RegionSize then begin
        Result := Mbi.RegionSize;
        AAddressOfLargest := Mbi.BaseAddress;
      end;
      Inc(P, Mbi.RegionSize);
    end else
      Inc(P, Si.dwPageSize);
  end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
  BaseAddr: pointer;
  MemSize: LongWord;
begin
  MemSize := GetLargestFreeMemRegion(BaseAddr);
  // allocate dynamic array of this size
  SetLength(fArrayOfBytes, MemSize - 16);

  Caption := Format('Largest address block: %u at %p; dynamic array at %p',
    [MemSize, BaseAddr, pointer(@fArrayOfBytes[0])]);
end;