问题
I am watching this video where Marco is talking about Automatic Reference Counting. I already knew that under Android and iOS (Firemonkey) my objects are ref counted so I don't need the try finally block.
Does the reference count implementation work according with the platform (VLC or FMX) or with the OS?
What I mean is:
var a: TObject;
begin
a := TObject.Create;
a.use1;
a.use2;
end;
This is good in Firemonkey if it runs on Android/iOS/Mac, I have no memory leak. But if I ran this under Windows (and I have used Firemonkey) do I still have the memory leak due to no ref count?
Anyway from the video I have understood that a try finally with a call of Free, even under ARC, is not bad usage but it's just useless.
回答1:
ARC is implemented per OS platform, not GUI framework.
The Android, iOS and Linux compilers use ARC memory management for objects. The Windows and OSX compilers use the classic manual memory management, where ARC is supported only on interface references, not objects.
VCL is a Windows-only framework, it runs only under classic compilers.
On the other hand, FMX as a cross-platform framework, and uses different memory management systems, depending on which OS platform it runs on.
try...finally Free blocks are indeed useless on ARC compilers (in context of safe-guarding object release in combination with Free method).
However, if you write cross-platform code that must work under both memory management systems, you must use try...finally and Free.
On the other hand, if you write code that only must work under ARC, you can safely omit try...finally and Free.
However, on ARC you may want to use Free (on ARC compiler it translates to nil assignment) or directly assign nil to object/interface reference if you need to release object at certain point, before it's reference would go out of scope.
There is one important exception to the above rules - TComponent descendants (that includes Firemonkey GUI components and controls) where try...finally Free blocks have to be replaced with try...finally DisposeOf if you are creating and releasing those instances in code.
You can read more at How to free a component in Android / iOS
Important thing to note here: DisposeOf has very specific purpose, it is not universal solution for breaking reference cycles and releasing objects under ARC. Using it blindly in all places can result in memory leaks. More elaborate answer can be found in above Q/A under Pitfalls of DisposeOf
回答2:
The reference count ARC is something very confusing under delphi, and it's make development much more harder that it's must be because it is badly designed (under delphi).
First it's build in RTL, and it's quite similar to what you have with String. it's work on plateform (firemonkey) and also on OS (work only on android/ios/unix). So if you want to build multi plateform code that target also window (most probable, a least just to debug you code) you will anyway need to keep the try ... finally .. end; (yes i say you, very bad design). so forget about your example without .free except if you want to debug under mobile (and good luck with 3 min compilation everytime, it's simply not possible)
NOTE: To keep you code compatible as most as possible a good rule to acquire is to replace all you .free by .disposeOF followed by nil because under mobile, free is a no-ops operation and you object is not destroyed, and can be destroyed at a very unexpected time (or simply never be destroyed in worst case, quite common if you use for example TTask). these scenarios are not so rare, especially if you use often anonymous procedure (reference to procedure) that create in the background capture to your object.
Always keep in mind that circular ref are quite easy to meet and quite hard to detect
.
after you must know also (you didn't ask, but i extend a little the answer) that their is delphi Tobject, java object, IOS objective C object and Interface. All have their own rules and confuse everyone and at the end no-one really know how it's work (yes part of the badly design of ARC is also the confusion it's gave), even emb developer do mistake in their delphi source code, look for exemple this question: delphi + ios: release / retain and reference counting with objective-c object that is quite trivial, but without any answer
ARC and Objective-C wrapped objects
Delphi NextGen compiler implements automatic reference counting (ARC) for all Delphi objects. The compiler will manage the logic to TObject’s __ObjAddRef and __ObjRelease for you. Objective-C code uses the same logic to call retain and release. Unfortunately there is no ARC for the Objective-C objects represented by the import wrapper class and the interfaces discussed above. When dealing with Objective-C objects you’ll have to call retain and release yourself at the correct points.
ARC and JAVA object
On the paper it's must work, but personally i don't trust it, for exemple if you do in loop :
for i := 0 to 100000 do begin
aJstring := StringToJstring('a text');
aStr := JstringToString(aJstring);
end;
normally this must run without any trouble in a normal world, but under delphi, it's will crash :( but anyway here you don't have .release so you don't have choice (except assigning the variable to nil). But when you have choice this why i recommend always to use .disposeOF followed by nil, you will probably win days/weeks/month of development escaping some nasty bug.
NOTE: i call this function when i want to destroy an object:
{******************************}
Procedure ALFreeAndNil(var Obj);
var Temp: TObject;
begin
Temp := TObject(Obj);
if temp = nil then exit;
TObject(Obj) := nil;
{$IF defined(AUTOREFCOUNT)}
if AtomicCmpExchange(temp.refcount{Target}, 0{NewValue}, 0{Compareand}) = 1 then begin // it's seam it's not an atomic operation (http://stackoverflow.com/questions/39987850/is-reading-writing-an-integer-4-bytes-atomic-on-ios-android-like-on-win32-win6)
temp.Free;
temp := nil;
end
else begin
Temp.DisposeOf; // TComponent Free Notification mechanism notifies registered components that particular
// component instance is being freed. Notified components can handle that notification inside
// virtual Notification method and make sure that they clear all references they may hold on
// component being destroyed.
//
// Free Notification mechanism is being triggered in TComponent destructor and without DisposeOf
// and direct execution of destructor, two components could hold strong references to each
// other keeping themselves alive during whole application lifetime.
{$IF defined(DEBUG)}
if (Temp.RefCount - 1) and (not $40000000{Temp.objDisposedFlag}) <> 0 then
ALLog('ALFreeAndNil', Temp.ClassName + ' | Refcount is not null (' + Inttostr((Temp.RefCount - 1) and (not $40000000{Temp.objDisposedFlag})) + ')', TalLogType.warn);
{$IFEND}
temp := nil;
end;
{$ELSE}
temp.Free;
temp := nil;
{$IFEND}
end;
In this way, if the refcount is not 0 after calling ALFreeAndNil, then it's generate a warning in the log (under debug) and you can investigate
来源:https://stackoverflow.com/questions/44374131/delphi-arc-under-firemonkey-for-windows