首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在ARC下数据库连接对象(Mydac TMyConnection)发生了什么?

在ARC下数据库连接对象(Mydac TMyConnection)发生了什么?
EN

Stack Overflow用户
提问于 2015-08-14 12:51:36
回答 1查看 591关注 0票数 1

我已经对ARC下的内存管理进行了研究,但我仍然不确定在这种情况下会发生什么。

代码语言:javascript
复制
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指定为0,或者打电话给DisposeOf来打破任何拒绝。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-08-14 20:38:40

我知道ARC对空闲对象使用引用计数,一旦超出作用域,对象就会被释放。

更准确地说,当它的引用计数降到0时,就会释放它。差别很大,因为如果仍然有其他的活动引用,变量可能会超出作用域,而不释放对象本身。

TMyConnection的活动连接会保持对象的作用域吗?

--它依赖于的几个因素:

  1. TMyQuery.Connection属性是否使用对TMyConnection对象的强引用或弱引用(即,支持其Connection属性的TMyQuery字段是否具有[weak]属性)。
  2. TMyQuery.Connection属性设置器是否在TMyConnection对象上调用FreeNotification()

让我们看看最好的情况-弱引用和不使用FreeNotification()

代码语言:javascript
复制
type
  TMyConnection = class(...)
    //...
  end;

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

代码语言:javascript
复制
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的引用计数不会增加,因此,当MyConMyQuery变量超出作用域时,两个对象引用计数都降到0,并且两个对象都被释放。

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

代码语言:javascript
复制
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;

代码语言:javascript
复制
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对象有两个对TMyConnection对象的强引用(一个用于支持Connection属性的字段,一个用于FreeNotification()列表),而TMyConnection具有对TMyQuery的强引用(在其FreeNotification()列表中),因此两个对象引用计数都会增加,并且在MyConMyQuery变量超出作用域时不会下降到0,因此这两个对象都会泄漏。

为什么FreeNotification()列表有很强的引用?因为在XE3中,Embarcadero将TComponent.FFreeNotifies成员从TList更改为TList<TComponent>。列表中的指针现在已经输入,当TList<T>TObject派生出来时,没有方法将T标记为保持弱指针,因此它们使用强引用。这是Embarcadero尚未解决的一个已知问题,因为XE8仍然在使用TList<TComponent>,而不是返回到TList,或者至少切换到TList<Pointer>

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

How to free a component in Android / iOS

我知道我总是可以把Mycon指定为0,或者打电话给DisposeOf来打破任何拒绝。

MyCon设置为零只会释放特定的引用,但不会对其他引用(如TMyQuery.Connection )产生任何影响。另一方面,调用MyCon.DisposeOf()将释放对象,并使所有强引用处于非零Disposed状态。

但是,在这种情况下,您应该能够清除MyQuery.Connection属性,让它有机会释放对TMyConnection对象的任何强大引用。这在上面描述的两种场景中都是有效的:

代码语言:javascript
复制
// 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!

代码语言:javascript
复制
// 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!
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32010583

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档