gpt4 book ai didi

delphi - ARC下数据库连接对象(Mydac TMyConnection)会发生什么

转载 作者:行者123 更新时间:2023-12-01 17:31:17 26 4
gpt4 key购买 nike

我研究过ARC下的内存管理但我仍然不确定在这种情况下会发生什么

function foo() : boolean
var
Mycon : TMyConnection
MyQuery : TMyQuery
begin
Mycon := TMyConnection.Create(nil);
Mycon.ConnectString := MyConnection1.ConnectString;
Mycon.ConnectionTimeout:= 3;
MyQuery := TMyQuery.Create(nil);
MyQuery.Connection := Mycon;
Mycon.Connect;

//Do a few Queries
end;

现在传统上来说,我会调用 Free 来释放它们,但我知道 ARC 使用引用计数来释放对象,一旦对象超出范围,就会被释放,在本例中,它是在查询之后被释放的。

现在我的问题是:TMyConnection 的事件连接会将对象保留在范围内吗?

我知道我总是可以将 Mycon 分配给 NIL 或调用 DisposeOf 来破坏任何引用。

最佳答案

I know ARC uses reference counting to free objects, And a object is freed once it goes out of scope

更准确地说,当它的引用计数降至 0 时,它就会被释放。差别很大,因为如果仍有其他事件引用,则变量可能会超出范围而对象本身不会被释放。

Would the active connection of the TMyConnection keep the object in scope?

这取决于几个因素:

  1. 是否TMyQuery.Connection属性使用引用 TMyConnection对象(即,支持其 TMyQuery 属性的 Connection 字段是否具有 [weak] 属性)。

  2. 是否TMyQuery.Connection属性(property)设置者来电FreeNotification()关于TMyConnection对象。

让我们看看最好的情况 - 引用并且没有 FreeNotification() :

type
TMyConnection = class(...)
//...
end;

TMyQuery = class(...)
private
[weak] FConn: TMyConnection;
published
property Connection: TMyConnection read FConn write FConn;
end;

function foo() : boolean
var
Mycon : TMyConnection
MyQuery : TMyQuery
begin
Mycon := TMyConnection.Create(nil); // <-- MyCon.RefCnt is now 1
Mycon.ConnectString := MyConnection1.ConnectString;
Mycon.ConnectionTimeout:= 3;
MyQuery := TMyQuery.Create(nil); // <-- MyQuery.RefCnt is now 1
MyQuery.Connection := Mycon; // <-- MyCon.RefCnt remains 1
Mycon.Connect;

*Do a few Queries*

end; // <-- MyCon.RefCnt drops to 0, MyQuery.RefCnt drops to 0, OK!

在这种情况下,由于 TMyQuery对象对 TMyConnection 具有引用对象,TMyConnection的引用计数不会增加。因此,当 MyCon 时,两个对象引用计数都降至 0。和MyQuery变量超出范围,两个对象都被释放。

现在让我们看看最坏的情况 - 引用和 FreeNotification() 。如果您将组件从 ARC 之前的版本迁移到基于 ARC 的系统而不重新编写它们来处理 ARC,您可能会遇到以下情况:

type
TMyConnection = class(...)
//...
end;

TMyQuery = class(...)
private
FConn: TMyConnection;
procedure SetConnection(AValue: TMyConnection);
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
published
property Connection: TMyConnection read FConn write SetConnection;
end;

procedure TMyQuery.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = FConn) then
FConn := nil;
end;

procedure TMyQuery.SetConnection(AValue: TMyConnection);
begin
if FConn <> AValue then
begin
if FConn <> nil then FConn.RemoveFreeNotification(Self);
FConn := AValue;
if FConn <> nil then FConn.FreeNotification(Self);
end;
end;

function foo() : boolean
var
Mycon : TMyConnection
MyQuery : TMyQuery
begin
Mycon := TMyConnection.Create(nil); // <-- MyCon.RefCnt is now 1
Mycon.ConnectString := MyConnection1.ConnectString;
Mycon.ConnectionTimeout:= 3;
MyQuery := TMyQuery.Create(nil); // <-- MyQuery.RefCnt is now 1
MyQuery.Connection := Mycon; // <-- MyCon.RefCnt is now 3, MyQuery.RefCnt is now 2
Mycon.Connect;

*Do a few Queries*

end; // <-- MyCon.RefCnt drops to 2, MyQuery.RefCnt drops to 1, LEAKS!

在这种情况下,由于 TMyQuery对象有 2 个对 TMyConnection引用对象(1 表示支持 Connection 属性的字段,1 在其 FreeNotification() 列表中),以及 TMyConnectionTMyQuery强烈引用(在其 FreeNotification() 列表中),当 MyCon 时,两个对象引用计数都会递增并且不会降至 0。和MyQuery变量超出范围,因此两个对象都被泄漏。

为什么 FreeNotification()列表有引用吗?因为在XE3中,Embarcadero改变了TComponent.FFreeNotifies来自 TList 的成员到 TList<TComponent> 。现在已经键入了列表中的指针,并且无法标记 TList<T>T 时持有弱指针源自TObject ,所以他们使用强引用。这是 Embarcadero 尚未解决的已知问题,因为 XE8 仍在使用 TList<TComponent>而不是回到TList或者至少切换到TList<Pointer> .

有关更多详细信息,请参阅此问题的答案:

How to free a component in Android / iOS

I know I could always just assign Mycon to NIL or call DisposeOf to break any refrences.

设置MyCon to nil 只会释放该特定引用,但不会对其他引用产生任何影响,例如 TMyQuery.Connection 。调用MyCon.DisposeOf()另一方面,会释放对象并将所有引用保留在非零 Disposed 中。状态。

但是,在这种情况下,您应该能够清除 MyQuery.Connection属性,使其有机会释放对 TMyConnection 的任何引用。目的。这适用于上述两种情况:

// weak referencing, no FreeNotifcation():

function foo() : boolean
var
Mycon : TMyConnection
MyQuery : TMyQuery
begin
Mycon := TMyConnection.Create(nil); // <-- MyCon.RefCnt is now 1
Mycon.ConnectString := MyConnection1.ConnectString;
Mycon.ConnectionTimeout:= 3;
MyQuery := TMyQuery.Create(nil); // <-- MyQuery.RefCnt is now 1
MyQuery.Connection := Mycon; // <-- MyCon.RefCnt remains 1, MyQuery.RefCnt remains 1
try
Mycon.Connect;
*Do a few Queries*
finally
MyQuery.Connection := nil; // <-- MyCon.RefCnt remains 1, MyQuery.RefCnt remains 1
end;
end; // <-- MyCon.RefCnt drops to 0, MyQuery.RefCnt drops to 0, OK!

// strong reference, FreeNotification():

function foo() : boolean
var
Mycon : TMyConnection
MyQuery : TMyQuery
begin
Mycon := TMyConnection.Create(nil); // <-- MyCon.RefCnt is now 1
Mycon.ConnectString := MyConnection1.ConnectString;
Mycon.ConnectionTimeout:= 3;
MyQuery := TMyQuery.Create(nil); // <-- MyQuery.RefCnt is now 1
MyQuery.Connection := Mycon; // <-- MyCon.RefCnt is now 3, MyQuery.RefCnt is now 2
try
Mycon.Connect;
*Do a few Queries*
finally
MyQuery.Connection := nil; // <-- MyCon.RefCnt drops to 1, MyQuery.RefCnt drops to 1
end;
end; // <-- MyCon.RefCnt drops to 0, MyQuery.RefCnt drops to 0, OK!

关于delphi - ARC下数据库连接对象(Mydac TMyConnection)会发生什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32010583/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com