delphi - 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 中工作时可能有一些特殊性?
解决方案
此问题并非特定于 Indy。显示的代码有可能同时运行数千个线程,每个线程占用一个内核对象,使用 1-4MB 的默认堆栈大小等。加起来,可能会使用大量内存和系统资源. 因此,随着循环的进行,新线程可能会随着ERROR_NOT_ENOUGH_MEMORY
时间的推移而失败,这是有道理的。
缓解这种情况的一种选择是减少每个线程的堆栈大小,因为此代码在每个线程中所做的工作很少,因此不需要大堆栈。TThread
直到 Delphi 10.3 Rio 才在每个线程的基础上提供此选项,但 Win32 API 一直支持它(请参阅如何在 TThread 中设置堆栈大小?)。或者,您可以在整个应用程序的项目设置中全局设置默认堆栈大小,或者在代码中通过{$MINSTACKSIZE}
.
另一种选择是减少同时运行的线程数。例如通过使用由限制运行任务数量的线程池运行的任务队列。
推荐阅读
- php - PHP重复字段多维数组
- azure - 调用 APIM 管理器 API 失败
- php - 如果 user_id 和 post_id 相同,如何从我的数据库中删除一个赞?
- sonarqube - 无法将 SonarQube 与 SQL 服务器连接
- spring - 为什么我的 Spring 导入语句不起作用?
- ios - SCNLevelOfDetails 委托/通知
- oracle - Oracle DB Developer 导入 .dmp 时出错
- sql - 了解引用触发操作的工作原理
- unity3d - 如何从中间点开始 Vector3.Lerp?
- php - 在编辑器上更新 header.php 时,Wordpress 主题崩溃