我知道这三种技巧:
1.#手动
uses
System.Classes;
procedure DoSomething;
var
sl: TStringList;
begin
sl := TStringList.Create;
try
finally
sl.Free; // Invoking destructor
end;
end;
1.#引用计数/接口(TInterfacedObject
)
标准库中最快的例子:
uses
Xml.XMLDoc, Xml.XMLIntf;
procedure DoSomething;
var
xmldoc: IXMLDocument;
begin
xmldoc := TXMLDocument.Create(nil) as IXMLDocument;
end; // No reference to xmldoc anymore, freed automatically
1.#所有权
就像几乎整个VC库或这个:
uses
System.Generics.Collections;
procedure DoSomething;
var
ol: TObjectList<TObject>;
i: Integer;
o: TObject;
begin
ol := TObjectList<TObject>.Create(true); // the list takes ownership of the objects
try
for i := 0 to 9 do begin
o := TObject.Create;
ol.Add(o);
end;
finally
ol.Free; // does not only free the list but all objects in the list, too
end;
end;
还有别的吗?
1条答案
按热度按时间9vw9lbht1#
在Delphi中,管理对象示例的内存管理模型有两种:手动内存管理和自动引用计数。所有对象示例都将手动释放或通过引用计数机制释放。
但是,当涉及到实际的编码模式时,我们可以通过多种方式编写代码来触发对象示例的释放,并且几乎不可能将它们全部列出和分类。
要说明所涉及的复杂性,最好的方法是提出额外的问题:
您认为内存管理技术是什么?
例如,手动释放对象示例需要调用析构函数。但有几种常用的方法可以做到这一点:通过调用
Free
、Destroy
或FreeAndNil
。但是,Free
和FreeAndNil
最终将调用Destroy
。所以问题是,我们应该认为调用析构函数的不同方法是相同的技术还是不同的技术?会触发对象示例销毁的其他定制编写方法怎么办?当涉及到释放引用计数的对象示例时,您的示例展示了间接释放的方法--只是让引用超出范围。但是还有另外一种方法来释放这种对象示例,那就是显式地将
nil
赋值给这种引用。同样,问题是我们认为这两个不同的例子是相同的还是不同的?
当涉及所有权时,它只是将释放对象示例委托给其他实体的一种方式。最后,在手动管理对象示例的情况下,某些代码将在某个点直接调用此类对象上的析构函数。虽然这显然是一种不同的编码模式,不需要经过额外的间接层就直接调用对象引用上的析构函数,但最终将手动释放示例。
我们还可以转移引用计数对象示例的所有权。如果您有一个持有接口引用的集合,那么这也可以被认为是所有权转移,因为这些示例的释放将取决于集合本身的释放,即使涉及的代码不会直接调用析构函数,但将依赖于自动引用计数来执行此操作。
随之而来的下一个问题是:字段怎么办?您的第一个示例显示了本地对象示例的构造和销毁。如果我们在类中有一个对象字段,并在其析构函数中手动调用
Free
到该字段,我们应该将其视为手动技术或所有权转移,因为内部对象示例的实际释放将取决于其外部拥有对象的释放。引用计数还有其他方面。虽然编译器自动在适当的位置插入引用计数代码(调用
_AddRef
和_Release
方法),但_Release
方法本身必须直接调用析构函数来实际释放示例。在某种程度上,这只是所有权转移的另一个例子,在一些编译器的帮助下。从一个Angular 来看,我们可以说您提到的这三种技术是释放对象示例的(两种)三种基本技术。但另一方面,它们的数量是无限的。