0

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.

Dalija Prasnikar
  • 27,212
  • 44
  • 82
  • 159
Emma Rossignoli
  • 935
  • 7
  • 25

2 Answers2

7

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

Dalija Prasnikar
  • 27,212
  • 44
  • 82
  • 159
  • Ok thank you. Yes I use try .. finally always because if I need a program to work on a different platform I won't have leaks (no matter the OS). – Emma Rossignoli Jun 05 '17 at 18:08
  • "*`try...finally` and `Free` are indeed useless on ARC compilers*" - that is misleading. They are *optional* on ARC system, but they are not *useless*. By manually `Free`ing an object, you are controlling *when* its reference count is decremented, which affects *when* the object is freed. You don't *have* to wait for an object to go out of scope if you need its refcount to decrement sooner rather than later. – Remy Lebeau Jun 05 '17 at 19:13
  • @RemyLebeau `try...finally` are useless on ARC. We can discuss `Free` - it does give you control over when your object will be released - but in context of usual `try...finally` blocks it is not necessary. Also in pure ARC code I prefer using `nil` instead of `Free`. – Dalija Prasnikar Jun 05 '17 at 19:21
  • 1
    @DalijaPrasnikar: The compiler will translate `Free` to `nil` for you. Like you said, for cross-platform coding, you have to use `Free`. But `try..finally` is NOT useless in ARC. You are focusing too much on one usage of it - creating an object and then freeing it. `try..finally` is not limited to just that usage, so don't say it is useless. – Remy Lebeau Jun 05 '17 at 19:57
  • @DalijaPrasnikar: I agree with Remy: there are many situations where you must protect resources other than memory (open files, locks, changed cursors, etc.) from exceptions, and then you still need `try...finally`. – Rudy Velthuis Jun 05 '17 at 20:09
  • 2
    @RudyVelthuis Yes, but question is about `try...finally` in context of memory management used together with `Free`. I don't see too much ambiguity here. I think it is quite clear that I am not talking about `try...finally` in general – Dalija Prasnikar Jun 05 '17 at 20:12
  • @Your statement stands as-is. And as-is, it is not correct. You don't need try-finally to protect the lifetime of objects, but certainly for other purposes. That should be made clear, IMO, as many people might think it is not needed at all anymore. – Rudy Velthuis Jun 05 '17 at 20:16
  • 1
    @RudyVelthuis I updated the answer. I hope it is clear now. – Dalija Prasnikar Jun 05 '17 at 20:20
  • @DalijaPrasnikar: `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` => can you please write just an example in you answer to show when DisposeOF (followed by nil of course) will generate leak AND free will not ? please! – zeus Jun 09 '17 at 09:17
  • @loki if you have such case then both Free and DisposeOf will leak, I have never said otherwise. Problem with using DisposeOf as some sort of safeguard is that you will make obvious issues less obvious. You are basically obscuring and hiding issues in your code instead of resolving them. If you have object instance that is not released with Free (or nil) it is very easy to test it and see that it is still alive. If nothing else simple breakpoint in destructor will tell you something is wrong. Finding out that object disposed object instance is leaking memory is much harder. – Dalija Prasnikar Jun 09 '17 at 11:10
  • @DalijaPrasnikar `If you have object instance that is not released with Free (or nil) it is very easy to test it and see that it is still alive` you know that this is totally false! Yes maybe for a 10 lines of code project you can pass 30 minutes to debug (with 5 min just to compile and run the app) to check if your object is correctly freeing but for your 1 million LOC, be serious it's not possible ! So please stop to say that disposeOF is dangerous, instead better say that ARC is a total mistake. DisposeOF is the not the perfect, for sure, but it's the only think we have .. – zeus Jun 09 '17 at 12:12
  • And as you are a great Delphi developer, you must know that with delphi, close to all objects have a Destructor implemented, and this where most of the trouble come. Of course we can forget (and loose) the last 25 years of delphi programming history to redraw everything, but again be serious ... DisposeOF have the only purpose to fire the Destroy, and this is very (very) important ! it's help to keep your code working with the good old code or programming behavior. For example, doing aPopup := TPopup.Create(aParent); then later aPopup.free will for exemple NEVER release the apopup. – zeus Jun 09 '17 at 12:18
  • @loki I am tired of discussing this. ARC has some rules. If you follow those rules you will be fine. No matter how small or big project is. If there are issues and sometimes you can bump into them you have to adapt your coding practice. This is true not only for Delphi and ARC but for all coding in other languages and tools. Your approach is like playing Russian roulette. You hope you will get lucky. If you want to code like that, fine. Just don't advise others to follow such extremely BAD PRACTICE. – Dalija Prasnikar Jun 09 '17 at 12:26
  • `TPopup` is `TComponent` descendant - this is where you have to use `DisposeOf` instead of `Free`. I think I have made that clear. – Dalija Prasnikar Jun 09 '17 at 12:27
  • @DalijaPrasnikar ahah if you are tired, so stop to say wrong think (or better to say stupidity but i want to stay polite) ... and remember it's you who start this discussion first, now not my fault you are out of argument... you admit that disposeOF + nil will in anyway not generate more leak than free, it's the opposite even because you admit that disposeOF can in some case be obligatory (like with Tcompoment and other, so yea we must be a source code expert to know what is and what is not), and you strongly discourage to use it saying it's a bad practice! that what i call a "paradox" :) – zeus Jun 09 '17 at 12:40
  • @loki Yes, using `DisposeOf` everywhere is bad, because it is not designed to work in all occasions. Please read carefully all I have written here and in other answer. Your advice consists of use `DisposeOf + nil` everywhere and hope for the best. My advice is learn the rules of ARC and when it is appropriate to use `DisposeOf` and when you have to use other cycle breaking mechanisms. It is not that hard. – Dalija Prasnikar Jun 09 '17 at 12:48
  • @DalijaPrasnikar can i ask you (if not inappropriate) the name of the mobile app you made ? seam you speak only with theory and i don't like this, people at emb listen people like you but at the end it's gave them a wrong view of the reality. for your information, using disposeOF instead of Free can help you to detect memory leak at 100% of the case :) Just need to write the good proc for this, because it's easy to detect detroyed object that are still in the memory at the instant T. Quite (totally) impossible with .free to do this because object can be still in memory for a good reason. – zeus Jun 09 '17 at 12:56
  • @loki I have written many. Latest ones are called ConstParamCrash, ARCCycle, ARCLeak... you get the picture. If you mean published and written in Delphi answer is none. I have found out that Delphi is not suitable as mobile development tool in my case. Giving Embarcadero wrong view of reality... I don't think so... I have been pointing issues in Delphi ARC (and related non-ARC) compiler since very beginning. That is why I know `DisposeOf` is not right tool for the job in each and every occasion. – Dalija Prasnikar Jun 09 '17 at 13:33
  • ahah "arcleak" return me this on google : https://www.youtube.com/watch?v=6m47YH4VqyA :) i m quite impressed i admit :) – zeus Jun 09 '17 at 15:37
0

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

zeus
  • 12,173
  • 9
  • 63
  • 184
  • Using `DisposeOf` everywhere is very bad recommendation. `DisposeOf` has several flaws and using it where not needed can introduce another set of problems. – Dalija Prasnikar Jun 06 '17 at 09:49
  • Can you please say me one of this flaws ? – zeus Jun 06 '17 at 09:59
  • Read QP reports mentioned in my [answer under Pitfalls of DisposeOf](https://stackoverflow.com/a/27926153/4267244) Also, DisposeOf by itself does not clear all reference cycles. So you may think you have released everything, but actually you didn't. – Dalija Prasnikar Jun 06 '17 at 10:02
  • Besides, bad recommendations about `DisposeOf`, your answer also mentions a whole a lot of things that are not related to object memory management in context of using `try...finally Free` blocks. Anonymous methods issues are related to variable capture (not related to question) and wrapping Objective-C and Java object also falls into completely different category. And AFAIK issue with Java string leaks is resolved in Tokyo. – Dalija Prasnikar Jun 06 '17 at 10:06
  • @DalijaPrasnikar about your sample you mentioned in your answer under Pitfalls of DisposeOf, yes you must always do DisposeOf + nil (something like DisposeOfAndNil) but anyway for these 2 pitfalls regarding disposeOF i can gave you 100 other regarding .FREE. Also yes disposeOF don't clear the reference count, but it's better to have in memory just the few bytes used by the size of pointer than the memory used by an object alive ;) – zeus Jun 06 '17 at 10:16
  • @DalijaPrasnikar - it's your opinion about DisposeOF (and if i remember well it's even you that first open a QR report to suggest to replace free by disposeOF) ! In the delphi source code i count 249 times the use of disposeOF ;) when people will understand that delphi is not (yet) java and can not work like it we will make a great step. Sorry i extend a little the answer (and i say it in the answer) but think it's important to have in mind (for exemple) that you variable can be easily captured and life much much more longer that what you think – zeus Jun 06 '17 at 10:27
  • @DalijaPrasnikar : about Downvoting, don't worry i m accommodated, their is one or 2 people here that always downvote everything i say, i don't care i m not looking for any job ... and ARC fan for sure will not like my answer ! but i suggest to them to work with java not delphi ;) – zeus Jun 06 '17 at 10:29
  • I filed that report 4 years ago. A lot has changed in the meantime. Unfortunately Delphi source code can no longer be used as example of 'good coding practices' – Dalija Prasnikar Jun 06 '17 at 10:30
  • yes change happen the last 4 years, but in the meantime if someone is able to gave me the name of a very great app made in delphi for mobile (so with ARC) I promise will not anymore boring anyone with arc .. But yes you are right, think are changing, but not in the good way :( – zeus Jun 06 '17 at 10:35
  • Free works fine. If it does not, then you have bug in your code that you need to correct. And yes ARC compiler has some issues but those don't imply Free itself is broken. – Dalija Prasnikar Jun 06 '17 at 10:39
  • it's not about free, free unfortunately (and it's the problem) do nothing in ARC, it's about to know WHEN your object will be free ... and trust the delphi code to do it for you it's simply the most craziest think to do (emb team have not the reputation to be the most cleaver), and it's not because it's will work ok in 95% of the case you must use it, because the 5% of the case when it's will not work will make you life hell and cost you 80% of the development time to debug everything (under mobile a 5min per compile). personally i prefere the try ... finally disposeOF end and win time ;) – zeus Jun 06 '17 at 10:43
  • DisposeOf + nil does not clear all circular references - it works only for destructor resolved ones - for example it works for TComponent notification system. Maybe you are satisfied with small leaks but that is extremely bad advice you are giving. – Dalija Prasnikar Jun 06 '17 at 11:36
  • Dalija their is no perfect solution ... i just say that with DisposeOF + nil you will reduce greatly the problem you will have by just using .free, but it's will not reduce all the problem. I M ABSOLUTELY NOT SATISFIED with small leak, but i m much more worried about BIG LEAK. also most of the trouble of delphi is that close to every object in delphi have the destructor implemented (that the main difference with java, sad emb team don't see it) and this behavior often require that when we do free we want often not to release memory but to call the destructor that do many think – zeus Jun 06 '17 at 11:46
  • also if you have little leak with disposeOF + nil, you will surely still have those (big this time) leak with free ;) – zeus Jun 06 '17 at 11:48
  • Since inner managed types including strings are not cleared before object memory is released you can also have humongous leaks using DisposeOf + nil depending on how large is the data you are storing inside. – Dalija Prasnikar Jun 06 '17 at 11:51
  • yes, but it's will exactly the same with free :) this why i ask so much emb to remove this horrible ARC from delphi ... without any success unfortunatly i think they probably use a java editor to write their delphi code and want to keep it :) – zeus Jun 06 '17 at 11:54
  • For the last time. If you have LEAK with Free, you need to FIX your code properly. How, that depends on situation. But trading one leak for another is NOT RIGHT. – Dalija Prasnikar Jun 06 '17 at 12:12
  • yeaa and you will surely say me how to detect LEAK under mobile with the low debuging tool we have :) If you want to spend month(s) debugging your app it's up to you ... as i say their in 0 great mobile app made with Delphi, and their is a good reason for this ! And if you have LEAK with free you will "probably" not have anymore those LEAK with disposeOF ... and also for the last time, disposeOF it's not only to release memory, it's mostly to call the method DESTROY of the object where in delphi we do many think in it (as opposite to java for example). – zeus Jun 06 '17 at 12:53
  • [Delphi ARC Leak Check Library](https://bitbucket.org/shadow_cs/delphi-leakcheck) – Dalija Prasnikar Jun 06 '17 at 13:06
  • i m curious how it's can detect memory leak because under arc object are not free from memory by you and the leaks in the app are often release by the compiler when you close the app ;) – zeus Jun 06 '17 at 13:35
  • also it's support only : Delphi XE7 - Delphi XE6 - Delphi XE5 - Delphi XE – zeus Jun 06 '17 at 13:39