Posts

Showing posts with the label Memory Management

Patterns for constructing reference-counted objects: Factory functions vs `as` operator

The construction of reference-counted object instances, which have automatic memory management, is a recurring topic. The main problem with such instances is that they need to be assigned to an interface reference (explicit or implicit) to have a properly initialized reference counting mechanism and a properly managed lifetime. There are many different coding patterns and scenarios around the construction and assignment of such instances. The simplest scenario is having an explicit interface reference to which we will assign the newly constructed object; in some, the compiler will lend us a hand and insert the appropriate code behind the scenes; and in some, it will do the opposite, due to either some compiler bugs or an ambiguity in the code which cannot be automatically resolved by the compiler. In previous blog posts, I have previously covered some such scenarios which needed special attention from developers to avoid bugs: Hello Old New Leaky Friend Inline Variables Type I...

Hello Old New Leaky Friend

Image
Developers that extensively use interfaces in Delphi probably know about a long-standing issue with the compiler, where interface parameters declared as const or [ref] will cause a memory leak if a reference-counted object instance is constructed directly at the call site. Illustration: Sandra Prasnikar        Specifically, the following code would create a leak: procedure LeakTest(const Intf: IInterface); begin end; procedure Run; begin LeakTest(TInterfacedObject.Create); end; begin ReportMemoryLeaksOnShutdown := True; Run; end. The problem arises because the compiler does not create a hidden interface reference that would properly initialize the reference counting mechanism and keep the object instance alive during the call. In other words, such an object would never be assigned to a strong interface reference. Because const and [ref] parameters don't trigger reference counting, if there is no other code within the called routine, the obj...

Zeroing Weak Object References

In the two-part post series, The purpose of weak references - Part I and The purpose of weak references - Part II , I wrote about the purpose of weak references in automatic reference counting, as well as in manual memory management, where they are commonly referred to as non-owning references. In ARC, object references to reference-counted objects are unsafe, non-zeroing weak references, and in manual memory management, non-owning references to an object instance are also unsafe. Unsafe, in the above context, means that you can safely use such references only if the object instance they point to always has a longer lifetime than the unsafe reference, or that there is additional mechanism (code) that will notify you when the object is destroyed, so you know the reference is not pointing to a valid object anymore. In manual memory management, TComponent implements such a notification mechanism. However, there are two downsides: first, it only works with TComponent descendants; and...

The purpose of weak references - Part II

Image
In the first part of this post series, I covered owning and non-owning references under manual memory management, and the purpose of non-owning (weak) references in that memory model. Following the same use cases, we can now clearly show the purpose of their counterparts under the automatic reference counting memory model. Automatic reference counting Automatic reference counting is a memory model under which an object instance will be valid as long as there is at least one strong reference to that object instance. When the last strong reference goes out of scope or is nilled, the object's reference count will drop to zero, and the instance will be automatically destroyed. One of the side-effects of that design is that two object instances that are no longer reachable through any outside references can hold strong references to each other, thus keeping themselves alive and creating memory leaks. This is called a reference cycle. To prevent problems with reference cycles, ARC h...

The purpose of weak references - Part I

Image
The terminology "weak and strong references" is commonly used in the context of automatic reference counting. In the context of manual memory management, we talk about ownership, and owning and non-owning references. While the terminology is different, those two different kinds of references represent the same concept, regardless of the underlying memory management model. Strong references are the equivalent of owning references, and weak references are the equivalent of non-owning references. Understanding those relations can help us understand the purpose of weak references in automatic reference counting, and instead of thinking about them merely in the context of breaking reference cycles, we should think about them as non-owning references—in other words, additional references to an object instance that don't participate in its memory management, and could be invalidated after the object is released through other code and owning references. Because non-owning (wea...

Mastering Delphi Memory Management Webinar Replay

Image
In case you missed the live session, webinar replay Mastering Delphi Memory Management where I am answering your questions about memory management is available on YouTube.  Book intro by Neven Prasnikar Jr. followed by a recording of live Q&A chat hosted by Jim McKeeth. Webinar replay: https://www.youtube.com/watch?v=_0_cUcygmLU Book info: https://dalija.prasnikar.info/delphimm Thank you all for joining live session and watching!

Delphi Memory Management Webinar

Image
Join me this Thursday, Apr 22, 2021 5:00 PM - 6:00 PM CEST for a live Q/A session about Delphi memory management. See you!  Register for webinar: https://register.gotowebinar.com/register/474961949731996432 Book information: https://dalija.prasnikar.info/delphimm  

Autorelease Pool

Manual memory management requires some thought and ceremony. It is not so much of a problem with long-lasting instances, but managing temporary local objects, especially when you need to create more than one, is a tedious job. It also hurts code readability. While Delphi allows automatic memory management for classes that implement interfaces, using ARC is not always feasible. If you have to deal with preexisting classes that don't support ARC, you will have to deal with manual memory management. Reference counting also adds some overhead, and using reference counting in your own classes is not always a viable approach. When performance is not paramount, simpler and cleaner code without try...finally blocks would be nice to have. Life always finds a way and various ARC-based smart pointer and similar lifetime management wrapper implementations have started to appear in the wild. One common place where constructing many object instances can be found is unit testing. While lifeti...

Magic behind FreeAndNil

Delphi 10.4 Sydney brings one small but rather significant change. A change in the signature of the FreeAndNil procedure from procedure FreeAndNil(var Obj); inline; to procedure FreeAndNil(const [ref] Obj: TObject); inline; Wait, const means the variable is passed as a constant and cannot be changed from within the procedure. But the whole point of FreeAndNil is to change the passed object variable to nil. What kind of sorcery is this? Let's start from the beginning and the old FreeAndNil procedure, its purpose and implementation. The purpose of FreeAndNil is to simplify the following code sequence: Foo.Free; Foo := nil; While the actual implementation of FreeAndNil is slightly different, and it will first nil the reference and then Free the object instance (temporarily preserved in a local variable), that slight difference is not relevant for discussing the signature of FreeAndNil . procedure FreeAndNil(var Obj); var Temp: TObject; begin Temp := TOb...

Listen to the Memory Manager

Let's say you have a nice, working Delphi application. One fine day, for no reason whatsoever, you decide to run your fine and bug free application with FastMM in full debug mode. Just for fun... and suddenly, out of the blue, the app starts crashing with an AV reading of address 0x80808088. What is going on... ???? When a seemingly working application suddenly starts misbehaving, the first instinct would be to look at the latest code change in searching for clues. In the above case, the only change was turning on FastMM debug mode. Could this be a bug in FastMM? While all software has bugs and it is perfectly possible that FastMM has bugs, too, it is highly unlikely that this is FastMM's fault. If turning on the CatchUseOfFreedInterfaces define in FastMM configuration shows an attempt to use an interface on a freed object, you have found the culprit. It may require further debugging and inspecting the code, but at least you will know what to look for. One of the ...

Unified Memory Management - Coming with 10.4 Beta

As announced on previous roadmaps, the 10.4 release of Delphi is planned to have unified memory management. That means retiring the ARC compiler on mobile platforms, which will now operate under the same good old manual memory management model that originated on Windows. Unification is good. Completely different memory management models require slightly different code. That alone breaks the promise of a single code base for all platforms. In reality, if you need to target platforms with different memory management models you will find yourself coding under the requirements of manual memory management where ARC will only throw you some curveballs. Constrained ARC is bad ARC, it is not useful, it cannot unleash its full power. On one side I am happy because of unification, on the other I am sad to see the ARC compiler go. It had great potential and was mostly brought down by unoptimized RTL/FMX code that was written for manual memory management. There is a whole lot of code that coul...

Self destructing object instance

Using reference counting classes always requires some caution. You have to pay attention to reference cycles, using interface reference for referencing such object instances, not calling FreeAndNil and more... it is quite a list... But every once in a while, new ways of shooting yourself in the foot keep popping up... So here goes the story... I have two reference counted classes that hold reference to each other instances. One of those references is marked as [weak] to prevent creating strong reference cycle. type TFoo = class(TInterfacedObject) private [weak] FRef: IInterface; public constructor Create(const ARef: IInterface); end; TBar = class(TInterfacedObject) private FFoo: IInterface; public constructor Create; virtual; destructor Destroy; override; procedure AfterConstruction; override; end; constructor TFoo.Create(const ARef: IInterface); begin ...

Deleaker

Image
If you have memory problems you should eat more... actually, I have no clue what you should do then. But if you have Delphi memory problems then Deleaker by Softanics can certainly be of assistance. Deleaker has integration with both Delphi (RAD Studio) and Visual Studio as well as standalone application. It can help you find various types of leaks in Windows applications - memory, GDI, handles in unmanaged and .NET applications. It has extremely low learning curve and you can start hunting memory leaks immediatelly. Thourough documentation and tutorials make this process even easier. Basically, it offers plug and play experience, something that is not commonly seen in non trivial developer tools. Hunting down memory leaks of any kind can be tedious and tiresome job, especially when leaks have gone out of control. One of the most usefull options that can help in pinpointing problems faster is Deleaker's ability to easily create memory snapshots while your program is runni...

Inline Variables Type Inference And Reference Counted Classes

There are two (OK, three) features I have been eagerly waiting for in Delphi. The ability to have multiple class helpers (aka extension methods) in scope Inline variables and (3.) type inference While I will have to wait some more for the former, Delphi Rio introduced the latter, making me a very happy camper. But it is not all perfect. Type inference does not work on reference counted classes. Or rather, it does work, but it breaks reference counting. For example, this inline variable declaration: var Ref := TInterfacedObject.Create; will be translated by the compiler into: var Ref: TInterfacedObject := TInterfacedObject.Create; In the above code, the compiler correctly infers the type - TInterfacedObject , but by doing so, it stores a reference counted object in an object reference. And as we all know, this kind of code breaks the reference counting mechanism. The famous "Don't mix objects and interfaces" rule. To properly initialize reference count...

ARC is dead, long live ARC

First, forgive me if some of my thoughts seem a bit contradictory or confusing. My brain is still steaming... and I am not sure what to think... Please, no... What took you so long... Nooooo.... But before, I start rationalizing... ARC IS NOT BROKEN, IT JUST NEEDS SOME POLISHING... I have been saying for a long time that the dual memory management model is not good in the long term and there should be only one memory management system, but by removing ARC in Linux compiler (10.3) and future plans to remove it from mobile compilers, I am afraid that Embarcadero have opted for the wrong one. Yes, ARC in Delphi has some issues, but those issues are fixable. Manual memory management is an obsolete technology. It has some niche use cases, but for general-purpose programming, you don't want to waste time on memory management. You want to focus on the real functionality of your code. To be fair, every memory management model has its strong and weak sides. Every one is more ...

Delphi Memory Management - Paperback Edition Released!

Image
Dear Gaia, I admit. I'm weak.  I caved in.  Please forgive me! Sincerely, Dalija I hope Gaia will accept my apology! I caved in to popular demand and have released a dead tree edition of my book. The first prints just came from Amazon (.com not the rain-forest... not sure about the origin of the paper, though...), and the book is ready for sale in its paperback form! You paperback lovers, you... You can find several ordering options, from eBook (PDF, epub, Mobi, Kindle all together at $37.50), single license or multi-developer site license, to Paperback (via Amazon, $45) and the bundle of both eBook & Paperback (ePixEditions/FastSpring and Lulu, together $60). You'll find all of this at:  http://dalija.prasnikar.info/delphimm/index.html

Don't mix objects and interfaces

Image
Mixing objects and interfaces in classic (non-ARC) Delphi is a huge no-no. That part is clear. What that actually means is more of a blur. After all there is a object instance lying behind every interface reference. So what is wrong with mixing objects and interfaces? object references are weak, interface references are strong reference counted object instances need at least one strong reference to keep them alive therefore you can't use object reference as primary owning reference reference counted object instances can be safely accessed through temporary, short-lived (weak) object references, as long as there are strong reference(s) keeping the object alive The real issue behind the mixing of objects and interfaces is not the mixing itself, but the lack of initial strong (interface) reference to object instance, or accessing the reference counted object instance through weak (object) reference after the last strong (interface) reference has gone out of scope and t...