Тут собраны совсем БАЗОВЫЕ объекты - типа TmsInterfacedNonRefcounted и TmsInterfacedRefcounted.
И которые поддерживают контроль за созданием/уничтожением:
http://programmingmindstream.blogspot.ru/2014/11/blog-post_8.html
http://programmingmindstream.blogspot.ru/2014/11/fastmm.html
Полезные ссылки:
http://18delphi.blogspot.ru/2013/04/iunknown.html
http://18delphi.blogspot.ru/2013/03/blog-post_4606.html
http://18delphi.blogspot.ru/2013/03/objective-c-delphi.html
Ну и "из жизни":
http://programmingmindstream.blogspot.ru/2014/11/fastmm.html?showComment=1417471861102#c4424285353046915141
Репозитарий:
https://bitbucket.org/ingword/mindstream/src/ee7a505dc542a2d71487a1b0e06ff2dc5827f9f1/Core/msCoreObjects.pas?at=MS-6_AddTestToMindStream
Код:
Ну и более "продвинутая версия":
-- она печатает в лог - список неосвобождённых экземпляров классов и их количество.
Ну и ещё. Используем TDictionary вместо TStringList.
P.S. Тут кстати есть ошибки. Скоро поправлю.
И которые поддерживают контроль за созданием/уничтожением:
http://programmingmindstream.blogspot.ru/2014/11/blog-post_8.html
http://programmingmindstream.blogspot.ru/2014/11/fastmm.html
Полезные ссылки:
http://18delphi.blogspot.ru/2013/04/iunknown.html
http://18delphi.blogspot.ru/2013/03/blog-post_4606.html
http://18delphi.blogspot.ru/2013/03/objective-c-delphi.html
Ну и "из жизни":
http://programmingmindstream.blogspot.ru/2014/11/fastmm.html?showComment=1417471861102#c4424285353046915141
Репозитарий:
https://bitbucket.org/ingword/mindstream/src/ee7a505dc542a2d71487a1b0e06ff2dc5827f9f1/Core/msCoreObjects.pas?at=MS-6_AddTestToMindStream
Код:
unit msCoreObjects; interface type TmsObjectsWatcher = class // - следилка за объектами // НЕ является ПОТОКОБЕЗОПАСНОЙ private class var f_ObjectsCreatedCount : Integer; public class procedure ObjectCreated(anObject: TObject); class procedure ObjectDestroyed(anObject: TObject); class destructor Destroy; end;//TmsObjectsWatcher TmsInterfacedNonRefcounted = class abstract(TObject) // - реализация объектов реализующих интерфейсы, но БЕЗ подсчёта ссылок // т.е. присваиваемы объект - НЕ ЗАХВАТЫВАЕТСЯ и "владелец" - НЕ УПРАВЛЯЕТ временем жизни // Зачем? Чтобы избежать кросс-ссылок. // От TmsInterfacedNonRefcounted должны наследоваться объекты-контейнеры, // которые хотят сообщать своим "детям" свои интерфейсы. // // Тут есть одна ТОНКОСТЬ - объект-контейнер - в СВОЮ очередь может являться // "ребёнком", но мы это потом - РАЗРУЛИМ, когда дойдём. public class function NewInstance: TObject; override; // ms-help://embarcadero.rs_xe7/libraries/System.TObject.NewInstance.html procedure FreeInstance; override; // ms-help://embarcadero.rs_xe7/libraries/System.TObject.FreeInstance.html protected function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end;//TmsInterfacedNonRefcounted TmsInterfacedRefcounted = class abstract(TInterfacedObject) // Реализация объектов, реализующих интерфейсы. С ПОДСЧЁТОМ ссылок. // // НЕ САМАЯ хорошая реализация, лучше реализация тут - http://18delphi.blogspot.ru/2013/04/iunknown.html // но в учётом ARC - пользуемся пока "нативной реализаией" // // Таже ещё есть вот что "почитать": // - http://18delphi.blogspot.ru/2013/07/blog-post_3683.html // - http://18delphi.blogspot.ru/2013/07/1.html // - http://18delphi.blogspot.ru/2013/07/2.html // - http://18delphi.blogspot.ru/2013/07/2_18.html // - http://18delphi.blogspot.ru/2013/07/blog-post_8789.html public class function NewInstance: TObject; override; // ms-help://embarcadero.rs_xe7/libraries/System.TObject.NewInstance.html procedure FreeInstance; override; // ms-help://embarcadero.rs_xe7/libraries/System.TObject.FreeInstance.html end;//TmsInterfacedRefcounted implementation // TmsObjectsWatcher class procedure TmsObjectsWatcher.ObjectCreated(anObject: TObject); begin Inc(f_ObjectsCreatedCount); end; class procedure TmsObjectsWatcher.ObjectDestroyed(anObject: TObject); begin Assert(f_ObjectsCreatedCount > 0, 'Какие-то объекты уже были освобождены несколько раз'); Dec(f_ObjectsCreatedCount); end; class destructor TmsObjectsWatcher.Destroy; begin Assert(f_ObjectsCreatedCount = 0, 'Какие-то объекты не освобождены'); end; // TmsInterfacedNonRefcounted class function TmsInterfacedNonRefcounted.NewInstance: TObject; begin Result := inherited NewInstance; TmsObjectsWatcher.ObjectCreated(Result); end; procedure TmsInterfacedNonRefcounted.FreeInstance; begin TmsObjectsWatcher.ObjectDestroyed(Self); inherited; end; function TmsInterfacedNonRefcounted.QueryInterface(const IID: TGUID; out Obj): HResult; begin Result := E_NoInterface; end; function TmsInterfacedNonRefcounted._AddRef: Integer; begin Result := -1; end; function TmsInterfacedNonRefcounted._Release: Integer; begin Result := -1; end; //TmsInterfacedRefcounted class function TmsInterfacedRefcounted.NewInstance: TObject; begin Result := inherited NewInstance; TmsObjectsWatcher.ObjectCreated(Result); end; procedure TmsInterfacedRefcounted.FreeInstance; begin TmsObjectsWatcher.ObjectDestroyed(Self); inherited; end; end.
Ну и более "продвинутая версия":
unit msCoreObjects;
interface
uses
System.Classes
;
type
TmsObjectsWatcher = class
// - следилка за объектами
// НЕ является ПОТОКОБЕЗОПАСНОЙ
private
class var f_ObjectsCreatedCount : Integer;
class var f_ObjectsCreated: TStringList;
// ms-help://embarcadero.rs_xe7/libraries/System.Classes.TStringList.html
public
class procedure ObjectCreated(anObject: TObject);
class procedure ObjectDestroyed(anObject: TObject);
class destructor Destroy;
end;//TmsObjectsWatcher
TmsWatchedObject = class abstract(TObject)
// - Класс, который умеетконтроллировать создание/уничтожение своих экземпляров
public
class function NewInstance: TObject; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.NewInstance.html
procedure FreeInstance; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.FreeInstance.html
end;//TmsWatchedObject
TmsStringList = class abstract(TStringList)
// - Класс, который умеетконтроллировать создание/уничтожение своих экземпляров
public
class function NewInstance: TObject; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.NewInstance.html
procedure FreeInstance; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.FreeInstance.html
end;//TmsStringList
TmsInterfacedNonRefcounted = class abstract(TmsWatchedObject)
// - реализация объектов реализующих интерфейсы, но БЕЗ подсчёта ссылок
// т.е. присваиваемы объект - НЕ ЗАХВАТЫВАЕТСЯ и "владелец" - НЕ УПРАВЛЯЕТ временем жизни
// Зачем? Чтобы избежать кросс-ссылок.
// От TmsInterfacedNonRefcounted должны наследоваться объекты-контейнеры,
// которые хотят сообщать своим "детям" свои интерфейсы.
//
// Тут есть одна ТОНКОСТЬ - объект-контейнер - в СВОЮ очередь может являться
// "ребёнком", но мы это потом - РАЗРУЛИМ, когда дойдём.
protected
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;//TmsInterfacedNonRefcounted
TmsInterfacedRefcounted = class abstract(TInterfacedObject)
// Реализация объектов, реализующих интерфейсы. С ПОДСЧЁТОМ ссылок.
//
// НЕ САМАЯ хорошая реализация, лучше реализация тут - http://18delphi.blogspot.ru/2013/04/iunknown.html
// но в учётом ARC - пользуемся пока "нативной реализаией"
//
// Таже ещё есть вот что "почитать":
// - http://18delphi.blogspot.ru/2013/07/blog-post_3683.html
// - http://18delphi.blogspot.ru/2013/07/1.html
// - http://18delphi.blogspot.ru/2013/07/2.html
// - http://18delphi.blogspot.ru/2013/07/2_18.html
// - http://18delphi.blogspot.ru/2013/07/blog-post_8789.html
public
class function NewInstance: TObject; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.NewInstance.html
procedure FreeInstance; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.FreeInstance.html
end;//TmsInterfacedRefcounted
implementation
uses
System.SysUtils
;
// TmsObjectsWatcher
class procedure TmsObjectsWatcher.ObjectCreated(anObject: TObject);
var
l_ClassName : String;
l_Index : Integer;
begin
Inc(f_ObjectsCreatedCount);
if (f_ObjectsCreated = nil) then
f_ObjectsCreated := TStringList.Create;
l_ClassName := anObject.ClassName;
l_Index := f_ObjectsCreated.IndexOf(l_ClassName);
if (l_Index < 0) then
f_ObjectsCreated.AddObject(l_ClassName, TObject(0))
else
f_ObjectsCreated.Objects[l_Index] := TObject(Integer(f_ObjectsCreated.Objects[l_Index]) + 1)
end;
class procedure TmsObjectsWatcher.ObjectDestroyed(anObject: TObject);
begin
Assert(f_ObjectsCreatedCount > 0, 'Какие-то объекты уже были освобождены несколько раз');
Dec(f_ObjectsCreatedCount);
end;
class destructor TmsObjectsWatcher.Destroy;
var
l_FS : TFileStream;
procedure OutLn(const aStr: ANSIString);
const
cEOL : ANSIString = #13#10;
begin//OutLn
l_FS.Write(aStr[1], Length(aStr));
l_FS.Write(cEOL[1], Length(cEOL));
end;//OutLn
var
l_Index : Integer;
begin
if (f_ObjectsCreatedCount > 0) then
begin
Assert(f_ObjectsCreated <> nil);
Assert(f_ObjectsCreated.Count > 0);
// Далее выводим статистику неосвобождённых объектов в лог:
l_FS := TFileStream.Create(ParamStr(0) + '.objects.log', fmCreate);
try
OutLn('Неосвобождено объектов: ' + IntToStr(f_ObjectsCreatedCount));
for l_Index := 0 to Pred(f_ObjectsCreated.Count) do
begin
if Integer(f_ObjectsCreated.Objects[l_Index]) > 0 then
OutLn(f_ObjectsCreated[l_Index] + ' : ' + IntToStr(Integer(f_ObjectsCreated.Objects[l_Index])));
end;//for l_Index
finally
FreeAndNil(l_FS);
end;//try..finally
f_ObjectsCreatedCount := 0;
// - чтобы дальше не падать
end;//f_ObjectsCreatedCount > 0
Assert(f_ObjectsCreatedCount = 0, 'Какие-то объекты не освобождены');
FreeAndNil(f_ObjectsCreated);
end;
// TmsWatchedObject
class function TmsWatchedObject.NewInstance: TObject;
begin
Result := inherited NewInstance;
TmsObjectsWatcher.ObjectCreated(Result);
end;
procedure TmsWatchedObject.FreeInstance;
begin
TmsObjectsWatcher.ObjectDestroyed(Self);
inherited;
end;
// TmsStringList
class function TmsStringList.NewInstance: TObject;
begin
Result := inherited NewInstance;
TmsObjectsWatcher.ObjectCreated(Result);
end;
procedure TmsStringList.FreeInstance;
begin
TmsObjectsWatcher.ObjectDestroyed(Self);
inherited;
end;
// TmsInterfacedNonRefcounted
function TmsInterfacedNonRefcounted.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
Result := E_NoInterface;
end;
function TmsInterfacedNonRefcounted._AddRef: Integer;
begin
Result := -1;
end;
function TmsInterfacedNonRefcounted._Release: Integer;
begin
Result := -1;
end;
//TmsInterfacedRefcounted
class function TmsInterfacedRefcounted.NewInstance: TObject;
begin
Result := inherited NewInstance;
TmsObjectsWatcher.ObjectCreated(Result);
end;
procedure TmsInterfacedRefcounted.FreeInstance;
begin
TmsObjectsWatcher.ObjectDestroyed(Self);
inherited;
end;
end.
-- она печатает в лог - список неосвобождённых экземпляров классов и их количество.
Ну и ещё. Используем TDictionary вместо TStringList.
unit msCoreObjects;
interface
uses
System.Classes,
System.Generics.Collections
;
type
TmsClassInstanceCountList = TDictionary<String, Integer>;
// ms-help://embarcadero.rs_xe7/libraries/System.Generics.Collections.TDictionary.html
TmsObjectsWatcher = class
// - следилка за объектами
// НЕ является ПОТОКОБЕЗОПАСНОЙ
private
class var f_ObjectsCreatedCount : Integer;
class var f_ObjectsCreated: TmsClassInstanceCountList;
public
class procedure ObjectCreated(anObject: TObject);
class procedure ObjectDestroyed(anObject: TObject);
class destructor Destroy;
end;//TmsObjectsWatcher
TmsWatchedObject = class abstract(TObject)
// - Класс, который умеетконтроллировать создание/уничтожение своих экземпляров
public
class function NewInstance: TObject; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.NewInstance.html
procedure FreeInstance; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.FreeInstance.html
end;//TmsWatchedObject
TmsStringList = class abstract(TStringList)
// - Класс, который умеетконтроллировать создание/уничтожение своих экземпляров
public
class function NewInstance: TObject; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.NewInstance.html
procedure FreeInstance; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.FreeInstance.html
end;//TmsStringList
TmsInterfacedNonRefcounted = class abstract(TmsWatchedObject)
// - реализация объектов реализующих интерфейсы, но БЕЗ подсчёта ссылок
// т.е. присваиваемы объект - НЕ ЗАХВАТЫВАЕТСЯ и "владелец" - НЕ УПРАВЛЯЕТ временем жизни
// Зачем? Чтобы избежать кросс-ссылок.
// От TmsInterfacedNonRefcounted должны наследоваться объекты-контейнеры,
// которые хотят сообщать своим "детям" свои интерфейсы.
//
// Тут есть одна ТОНКОСТЬ - объект-контейнер - в СВОЮ очередь может являться
// "ребёнком", но мы это потом - РАЗРУЛИМ, когда дойдём.
protected
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;//TmsInterfacedNonRefcounted
TmsInterfacedRefcounted = class abstract(TInterfacedObject)
// Реализация объектов, реализующих интерфейсы. С ПОДСЧЁТОМ ссылок.
//
// НЕ САМАЯ хорошая реализация, лучше реализация тут - http://18delphi.blogspot.ru/2013/04/iunknown.html
// но в учётом ARC - пользуемся пока "нативной реализаией"
//
// Таже ещё есть вот что "почитать":
// - http://18delphi.blogspot.ru/2013/07/blog-post_3683.html
// - http://18delphi.blogspot.ru/2013/07/1.html
// - http://18delphi.blogspot.ru/2013/07/2.html
// - http://18delphi.blogspot.ru/2013/07/2_18.html
// - http://18delphi.blogspot.ru/2013/07/blog-post_8789.html
public
class function NewInstance: TObject; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.NewInstance.html
procedure FreeInstance; override;
// ms-help://embarcadero.rs_xe7/libraries/System.TObject.FreeInstance.html
end;//TmsInterfacedRefcounted
implementation
uses
System.SysUtils
;
// TmsObjectsWatcher
class procedure TmsObjectsWatcher.ObjectCreated(anObject: TObject);
var
l_ClassName : String;
begin
Inc(f_ObjectsCreatedCount);
if (f_ObjectsCreated = nil) then
f_ObjectsCreated := TmsClassInstanceCountList.Create;
l_ClassName := anObject.ClassName;
if (not f_ObjectsCreated.ContainsKey(l_ClassName)) then
f_ObjectsCreated.Add(l_ClassName, 0)
else
f_ObjectsCreated.Items[l_ClassName] := f_ObjectsCreated.Items[l_ClassName] + 1;
end;
class procedure TmsObjectsWatcher.ObjectDestroyed(anObject: TObject);
begin
Assert(f_ObjectsCreatedCount > 0, 'Какие-то объекты уже были освобождены несколько раз');
Dec(f_ObjectsCreatedCount);
end;
class destructor TmsObjectsWatcher.Destroy;
var
l_FS : TFileStream;
procedure OutLn(const aStr: ANSIString);
const
cEOL : ANSIString = #13#10;
begin//OutLn
l_FS.Write(aStr[1], Length(aStr));
l_FS.Write(cEOL[1], Length(cEOL));
end;//OutLn
var
l_Index : Integer;
l_A : TArray<TPair<String, Integer>>;
begin
if (f_ObjectsCreatedCount > 0) then
begin
Assert(f_ObjectsCreated <> nil);
Assert(f_ObjectsCreated.Count > 0);
// Далее выводим статистику неосвобождённых объектов в лог:
l_FS := TFileStream.Create(ParamStr(0) + '.objects.log', fmCreate);
try
OutLn('Неосвобождено объектов: ' + IntToStr(f_ObjectsCreatedCount));
l_A := f_ObjectsCreated.ToArray;
for l_Index := 0 to Pred(f_ObjectsCreated.Count) do
begin
if (l_A[l_Index].Value > 0) then
OutLn(l_A[l_Index].Key + ' : ' + IntToStr(l_A[l_Index].Value));
end;//for l_Index
finally
FreeAndNil(l_FS);
end;//try..finally
f_ObjectsCreatedCount := 0;
// - чтобы дальше не падать
end;//f_ObjectsCreatedCount > 0
Assert(f_ObjectsCreatedCount = 0, 'Какие-то объекты не освобождены');
FreeAndNil(f_ObjectsCreated);
end;
// TmsWatchedObject
class function TmsWatchedObject.NewInstance: TObject;
begin
Result := inherited NewInstance;
TmsObjectsWatcher.ObjectCreated(Result);
end;
procedure TmsWatchedObject.FreeInstance;
begin
TmsObjectsWatcher.ObjectDestroyed(Self);
inherited;
end;
// TmsStringList
class function TmsStringList.NewInstance: TObject;
begin
Result := inherited NewInstance;
TmsObjectsWatcher.ObjectCreated(Result);
end;
procedure TmsStringList.FreeInstance;
begin
TmsObjectsWatcher.ObjectDestroyed(Self);
inherited;
end;
// TmsInterfacedNonRefcounted
function TmsInterfacedNonRefcounted.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
Result := E_NoInterface;
end;
function TmsInterfacedNonRefcounted._AddRef: Integer;
begin
Result := -1;
end;
function TmsInterfacedNonRefcounted._Release: Integer;
begin
Result := -1;
end;
//TmsInterfacedRefcounted
class function TmsInterfacedRefcounted.NewInstance: TObject;
begin
Result := inherited NewInstance;
TmsObjectsWatcher.ObjectCreated(Result);
end;
procedure TmsInterfacedRefcounted.FreeInstance;
begin
TmsObjectsWatcher.ObjectDestroyed(Self);
inherited;
end;
end.
P.S. Тут кстати есть ошибки. Скоро поправлю.
Комментариев нет:
Отправить комментарий