首页 > 解决方案 > Delphi Indy connect/disconnect 没有足够的内存资源来处理这个命令

问题描述

我本地化了我的 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 中工作时可能有一些特殊性?

标签: delphicrashindy

解决方案


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

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

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


推荐阅读