我一直在尝试追踪 Jedi VCL 中的内存泄漏JvHidControllerClass.pas
,我在源历史记录中遇到了这种变化:
旧版本:
constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice);
begin
inherited Create(True);
Device := Dev;
NumBytesRead := 0;
SetLength(Report, Dev.Caps.InputReportByteLength);
end;
当前版本:
constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice);
begin
inherited Create(False);
Device := Dev;
NumBytesRead := 0;
SetLength(Report, Dev.Caps.InputReportByteLength);
end;
根据经验,我发现如果您创建一个未挂起的线程:
inherited Create(False);
然后线程立即开始运行。在这种情况下,它将尝试访问尚未初始化的对象:
procedure TJvHidDeviceReadThread.Execute;
begin
while not Terminated do
begin
FillChar(Report[0], Device.Caps.InputReportByteLength, #0);
if Device.ReadFileEx(Report[0], Device.Caps.InputReportByteLength, @DummyReadCompletion) then
立即尝试填充Report
并访问该对象Device
。问题是它们还没有被初始化;这些是线程开始后的下一行:
Device := Dev;
NumBytesRead := 0;
SetLength(Report, Dev.Caps.InputReportByteLength);
我意识到这是一种竞争条件;并且用户在生产中遇到崩溃的可能性非常低,因此离开赛车崩溃可能是无害的。
但我走远了吗?我错过了什么吗?是否调用:
BeginThread(nil, 0, @ThreadProc, Pointer(Self), Flags, FThreadID);
不启动线程并立即运行?这真的是(故意)添加到 JVCL 中的竞争条件回归吗?有什么秘密吗
CreateSuspended(False);
这使它成为正确的代码:
CreateSuspended(True);
...
FDataThread.Resume;
?
在被误叫而被烧毁后
TMyThread.Create(False)
我已经将它归档在我的脑海中,因为它永远不会正确。让线程立即启动(当您必须初始化值时)是否有任何有效用途?