【问题标题】:Delphi Indy connect/disconnect Not enough memory resources are available to process this commandDelphi Indy connect/disconnect 没有足够的内存资源来处理这个命令
【发布时间】:2021-09-30 15:59:50
【问题描述】:

我本地化了我的 Delphi 服务应用程序的问题。

现在我有一台装有 Windows Server 2019、RDP 的测试服务器。

简单的测试代码,连接本地TCP服务器并断开连接:

for i := 1 to 1000000 div 100 do

begin

sleep(100);

Caption := 'STRESS TEST: ' + inttostr(i * 100);
Application.ProcessMessages;

for j := 1 to 100 do
begin

  thread := TThread.CreateAnonymousThread(
  procedure
  Var tcpClient : TIdTcpClient;
  begin

      try
        tcpClient := TIdTCPClient.Create(nil);
        tcpClient.Host := '127.0.0.1';
        tcpClient.Port := RollControl_Svc.TCPServer.Bindings[0].Port
        tcpClient.Connect;
        tcpClient.IOHandler.ReadTimeout := 1000;
      finally
        FreeAndNil(tcpClient);
      end;

  end);
  thread.FreeOnTerminate := (j > 1) and (j < 100);

  if thread.FreeOnTerminate then thread.Start else
  begin
    thread.Start;
    thread.WaitFor;
    thread.Free;
  end;

end;

在测试机上运行20K后,出现错误:

Thread creation error: Not enough memory resources are available to process this command.

在我使用机器时,一切都很好,已经完成了 100 万次操作。我有 Delphi XE3,最新的 Indy 版本,怎么了?也许在 RDP 中工作时有一些特殊性?

【问题讨论】:

  • "What's wrong?" - 错误信息很准确:对于您正在运行的进程,内存是有限的,并且您占用的内存太多,应该释放一些在要求更多之前再一次。想想你的“我的工作”机器有 16 GiB 的 RAM,而“测试服务器”只有 512 MiB 的 RAM。而服务在上面有更严格的限制。
  • 内存中的进程没有增长,它的大小只有100M。没有内存泄漏,句柄和线程的数量没有增加。在一个机器上它工作正常,第二个崩溃了这个错误
  • 你的代码中有很多奇怪的东西。让我只提其中一个:tcpClient := TIdTCPClient.Create(nil); 必须是try 之前的行。
  • @Andreas Rejbrand 我同意,但这不会影响问题。我移动了 tcpClient := TIdTCPClient.Create(nil);退出尝试块,问题没有消失
  • @НиколайНевзоров:我知道。

标签: delphi crash indy


【解决方案1】:

此问题并非特定于 Indy。显示的代码有可能同时运行 数千个 线程,每个线程占用一个内核对象,使用 1-4MB 的默认堆栈大小等。加起来,这就是很多可能正在使用的内存和系统资源。因此,随着循环的进行,随着时间的推移,新线程可能ERROR_NOT_ENOUGH_MEMORY 失败是有道理的。

缓解这种情况的一个选择是减少每个线程的堆栈大小,因为此代码在每个线程中做的工作很少,因此不需要大堆栈。 TThread 直到 Delphi 10.3 Rio 才在每个线程的基础上提供此选项,但 Win32 API 一直支持它(请参阅 How to set stack size in TThread?)。或者,您可以在整个应用程序的项目设置中全局设置默认堆栈大小,或通过{$MINSTACKSIZE} 在代码中设置。

另一个选择是减少同时运行的线程数。例如通过使用由限制运行任务数量的线程池运行的任务队列。

【讨论】:

    【解决方案2】:

    是的,这不是印地语

    下一个代码:

      no := 0;
      List := TList.Create;
    
      while true do
      begin
    
        Caption := 'STRESS TEST: ' + inttostr(no);
        Application.ProcessMessages;
    
        List.Clear;
    
        for j := 1 to 1000 do
        begin
          inc(no);
    
          Thread := TThread.CreateAnonymousThread(
            procedure
            begin
            end
            );
    
          thread.FreeOnTerminate := false;
          thread.Start;
          List.Add(thread)
        end;
    
        while List.Count > 0 do
        begin
         TThread(List[0]).WaitFor;
         TThread(List[0]).Free;
         List.Delete(0);
        end;
    
      end;
    

    400K 操作后,测试机出现错误。我不明白为什么。干净的代码,所有线程都在一个循环中创建和销毁。本地测试通过 1000 万次操作,测试 PC 仅 400K 失败

    【讨论】:

    • 防病毒软件可能会导致像这样的微基准测试/压力测试出现问题 - 它们通常会挂接到内核,以便在线程创建/销毁时收到通知,并可能在幕后导致额外的资源分配/使用。当线程进行实际工作时,效果通常会消失。
    【解决方案3】:

    无法重现此问题,因为我假设主机位于本地网络上。这可能取决于您安装的内存数量。如果它是图形密集型的,它也可能归结为 vram(显卡内存)。最好的办法是复制代码,但对于一个普通的基本网站,如果它有效,你知道它是一个 ram/vram 问题

    【讨论】:

      猜你喜欢
      • 2020-09-07
      • 2021-12-17
      • 1970-01-01
      • 2021-04-20
      • 2010-10-07
      • 2018-08-30
      • 2014-01-24
      • 1970-01-01
      • 2010-10-28
      相关资源
      最近更新 更多