【问题标题】:Delphi XE7 Android Creating Thread Error After Running about 2000000 timesDelphi XE7 Android 运行大约 2000000 次后创建线程错误
【发布时间】:2026-01-12 19:00:01
【问题描述】:

提前感谢您的宝贵时间。

先发简单的代码。

TSubThread 代码

TSubThread = class(TThread)
protected
  procedure Execute; override;
public
  constructor Create;
  destructor Destroy; override;
end;

procedure TSubThread.Execute;
begin
// do nothing
end;

constructor TSubThread.Create;
begin
  inherited Create(True);
  Self.FreeOnTerminate:= False;
end;

TMainThread的代码

TMainThread = class(TThread)
private
  FCounterOK,
  FCounterErr:int64;
  function FGetCounterOK:Int64;
  function FGetCounterErr:Int64;
protected
  procedure Execute; override;
public
  property CountOK:Int64 read FGetCounter;
  property CountErr:Int64 read FGetCounterErr;
  constructor Create;
  destructor Destroy; override;
end;

function TMainThread.FGetCounterOK:Int64;
begin
  result:= TInterlocked.Read(Self.FCounterOK);
end;

function TMainThread.FGetCounterErr:Int64;
begin
  result:= TInterlocked.Read(Self.FCounterErr);
end;

procedure TMainThread.Execute;
const
  CSTMaxThreads = 20;
var
  i: Integer;
  los:TArray<TSubThread>;
begin
  try
    while not Self.Terminated do
    begin
      //Create instance of TSubThread and append to DynArray
      while Length(los) < CSTMaxThreads do
      begin
        try
          l:= TSubThread.Create;
          los:= los + [l];
          l.Start;
          TInterLocked.Increment(Self.FCounterOK);
        except on E:System.SysUtils.Exception do
          TInterLocked.Increment(Self.FCounterErr);
        end;
      end;

      for i:= Length(los)-1 downto 0 do
      begin
      // Free thread Object
        if los[i].Finished then
        begin
          los[i].DisposeOf;
          los[i]:= nil;
          Delete(los,i,1);
        end;
      end;

    end;

  finally
    // MainThread  Terminated, Free all.
    for i := Length(los)-1 downto 0 do
    begin
      los[i].DisposeOf;
      los[i]:= nil;
    end;
    delete(los,0,Length(los));
  end;
end;

使用 E.ToString = "Create error: Try again." 在 Android 平台上运行大约 1800000 ~ 2000000 次(通过 CounterOK 和 CounterErr 属性)后创建 TSubThread 引发异常...并且相同的程序在 Windows 上运行完美和IOS。 代码有问题吗?

【问题讨论】:

  • 我不明白你为什么打电话给DisposeOf()。当引用计数达到零时,只需将对象设置为 nil 就会将对象从堆中丢弃。变量l 未声明,我假设它是Execute 方法的本地变量。在线程创建while循环后尝试将其设置为nil,只是为了摆脱最后创建的子线程的额外引用计数。
  • TThread 对 ARC 非常挑剔,因此您必须非常小心。自首次添加 ARC 以来,TThread 在每个版本中都受到 ARC 问题的困扰。
  • @LU RD DisposeOf() 是从 System.Classes 中的方法 ThreadProc() 复制而来的。当 thread.FreeOnTerminate=true 时,ThreadProc() 将调用 Thread.DisposeOf 并且不会发生任何问题。
  • 用线程变量替换动态线程数组可以避免这个问题。我的动态数组操作有问题吗?

标签: android multithreading delphi dynamic-arrays


【解决方案1】:

我很确定这里的问题是您产生了太多线程并且耗尽了资源来支持它们的存在。一旦 Execute 完成但在实际的底层线程被清理之前,TThread 设置完成。 DisposeOf 将调用析构函数,但这仍然只使用 WaitFor 检查是否完成,因此可能仍会为底层线程留下未完成的清理。管理所有平台上的线程销毁一直存在问题,我很确定您会发现这就是这里发生的事情。很长很长一段时间以来,我一直采用内部重用和 freeonterminate true 操作线程池来避免这些问题。

【讨论】:

  • 是的,有几种方法可以避免这个问题,将 freeonterminate 设置为 true 就是其中之一。或者用子线程变量替换动态数组。
最近更新 更多