为什么反复创建释放多线程TTHREAD对象会引起内存溢出

时间:2021-08-11 17:33:35
我做了一个TTHREAD对象,里面就一个简单的字符串替换函数,其他什么都没有,也没有操作VCL

我在程序中会反复创建 并释放它,没有用 terminatethread 和exitthread,因为我用了freeonterminate:=true; 根据跟踪可以看到线程正常结束了,用CheckThreadFreed 也可以得到结束释放的返回。

但我的程序中有一个TADOQUERY的过程,创建一个TADOQUERY执行一个查询后释放。

程序运行中,会出现 outofmemory 错误,FASTMM提示“FastMM 已检测到一个错误, 当时正在进行 GetMem 操作. FastMM 检测到对已释放内存块内容的修改.”

但事实上,我的每个对象都有成对且有效的creat和free,在释放后,也没有对该对象进行操作。

 
对堆栈跟踪可以看到,是在新创建一个对象时,出现的。

当前线程的 ID 是 0x1F5C, 导致该错误的堆栈跟踪(返回地址): 
40B3D4 [FastMM4][DebugGetMem]
40B62E [FastMM4][DebugReallocMem]
402F2F [System][@ReallocMem]
424C54 [Classes][TList.SetCapacity]
424ABC [Classes][TList.Grow]
4248CD [Classes][TList.Add]
42DE29 [Classes][TComponent.Insert]
42DE84 [Classes][TComponent.InsertComponent]
42DCCA [Classes][TComponent.Create]
4A3C40 [DB][TField.Create]
4A5517 [DB][TStringField.Create]


然后我不用这个TADOQUERY的过程,发现只要有其他需要分配内存的代码执行(对象自己的create)都会引起这种outofmemory。

我该怎么办?

9 个解决方案

#1


无限制的创建线程,而不释放,系统会承受不起的,不要滥用线程

#2


释放了的

从FASTMM中也可以看到

该内存块上一次分配于线程 0x2C3C, 当时的堆栈跟踪(返回地址): 
402EF4 [System][@GetMem]
4042AF [System][TObject.NewInstance]
40468A [System][@ClassCreate]
42E355 [Classes][TThread.Create]
477518 [Controls][TWinControl.WndProc]
474287 [Controls][TControl.Perform]
79DC1E [work.pas][work][FW_synword][5407]
78757C [work.pas][work][addviewboxblank][421]
793DEA [work.pas][work][FW_getuserpara][3313]
78A551 [work.pas][work][TFrm_work.workfile][1181]
78BBB4 [work.pas][work][TFrm_work.Timer_timeoutTimer][1533]

该内存块上次被用于一个属于以下类的对象: Tsynthread

分配号码是: 163504

该内存块上一次释放于线程 0x257C, 当时的堆栈跟踪(返回地址): 
402F1F [System][@FreeMem]
4042CD [System][TObject.FreeInstance]
4046D5 [System][@ClassDestroy]
42E46F [Classes][TThread.Destroy]
404313 [System][TObject.Free]
42E322 [Classes][ThreadProc]
4051FE [System][ThreadWrapper]
7C82482F [Unknown function at GetModuleHandleA]

线程,有创建和释放。

#3


把FreeOnTerminate去掉,原因是你设置了线程的FreeOnTerminate,这样会导致线程执行完毕的时候,自动释放线程对象,这样就导致了这个线程对象是在主线程中申请的,但是在分线程释放的,一般解决办法是线程执行完毕手动释放。

#4


在编写线程的时候,要遵守基本的原则,即本线程申请的内存,本线程负责释放,主线程申请的TThread,应该在主线程释放,而不是用FreeOnTerminate来释放。

#5


这个是我测试用的,
用freeonterminate是为了我真正要用的线程,里面使用了Indy的idftp,它会因某些原因阻塞而死锁,用tthread.free时,因为它会waitfor,结果程序就会无响应死掉。

用freeonterminate,当出现这种情况,我就可以不去管它,等关掉程序时会释放这种卡死的线程。

#6


另外,我测试了在主线程使用 free,仍然会出现outofmemory,有时不报错,直接就把程序自动关闭了。

#7


Out Of Memory是内存用光了,用FastMM多检查一下。

#8


outofmemory应该是SQLDebug_Fan 所说的原因,线程自释放会出问题,应该和delphi7的内存管理有关。

但是,现在仍然存在的问题就是不断创建、释放,然后某个时刻 程序崩溃,自动关闭。

我观察任务管理器,线程数量一直稳定在10-11,因为我同时只用了一个线程,创建后就11,释放后就10,句柄数也很稳定。

不知道为什么会崩溃,FASTMM跟踪不到,eurekalog也跟踪不到。

#9


确认TTHREAD类不能用自释放

#1


无限制的创建线程,而不释放,系统会承受不起的,不要滥用线程

#2


释放了的

从FASTMM中也可以看到

该内存块上一次分配于线程 0x2C3C, 当时的堆栈跟踪(返回地址): 
402EF4 [System][@GetMem]
4042AF [System][TObject.NewInstance]
40468A [System][@ClassCreate]
42E355 [Classes][TThread.Create]
477518 [Controls][TWinControl.WndProc]
474287 [Controls][TControl.Perform]
79DC1E [work.pas][work][FW_synword][5407]
78757C [work.pas][work][addviewboxblank][421]
793DEA [work.pas][work][FW_getuserpara][3313]
78A551 [work.pas][work][TFrm_work.workfile][1181]
78BBB4 [work.pas][work][TFrm_work.Timer_timeoutTimer][1533]

该内存块上次被用于一个属于以下类的对象: Tsynthread

分配号码是: 163504

该内存块上一次释放于线程 0x257C, 当时的堆栈跟踪(返回地址): 
402F1F [System][@FreeMem]
4042CD [System][TObject.FreeInstance]
4046D5 [System][@ClassDestroy]
42E46F [Classes][TThread.Destroy]
404313 [System][TObject.Free]
42E322 [Classes][ThreadProc]
4051FE [System][ThreadWrapper]
7C82482F [Unknown function at GetModuleHandleA]

线程,有创建和释放。

#3


把FreeOnTerminate去掉,原因是你设置了线程的FreeOnTerminate,这样会导致线程执行完毕的时候,自动释放线程对象,这样就导致了这个线程对象是在主线程中申请的,但是在分线程释放的,一般解决办法是线程执行完毕手动释放。

#4


在编写线程的时候,要遵守基本的原则,即本线程申请的内存,本线程负责释放,主线程申请的TThread,应该在主线程释放,而不是用FreeOnTerminate来释放。

#5


这个是我测试用的,
用freeonterminate是为了我真正要用的线程,里面使用了Indy的idftp,它会因某些原因阻塞而死锁,用tthread.free时,因为它会waitfor,结果程序就会无响应死掉。

用freeonterminate,当出现这种情况,我就可以不去管它,等关掉程序时会释放这种卡死的线程。

#6


另外,我测试了在主线程使用 free,仍然会出现outofmemory,有时不报错,直接就把程序自动关闭了。

#7


Out Of Memory是内存用光了,用FastMM多检查一下。

#8


outofmemory应该是SQLDebug_Fan 所说的原因,线程自释放会出问题,应该和delphi7的内存管理有关。

但是,现在仍然存在的问题就是不断创建、释放,然后某个时刻 程序崩溃,自动关闭。

我观察任务管理器,线程数量一直稳定在10-11,因为我同时只用了一个线程,创建后就11,释放后就10,句柄数也很稳定。

不知道为什么会崩溃,FASTMM跟踪不到,eurekalog也跟踪不到。

#9


确认TTHREAD类不能用自释放