Memory management

Understanding how built-in data types work also means knowing how Delphi manages the memory for them. It helps if you know at least something about Delphi and memory in general. Admittedly, this is a deep topic; something that most programmers—even excellent programmers—only understand in general terms. In other words, don't worry, you can safely forget 90% of the stuff I told you in Chapter 4Memory Management, and you'll still know enough.

When a Delphi program is running, memory is constantly being allocated, reallocated, and freed. This happens when classes are created and destroyed, when the length of a dynamic array is changed, when strings are modified, lists appended, and so on. If you want your code to perform well, you should be aware of this.

Instead of appending to a string, character by character, you would call SetLength to preallocate the target length (or some approximation of it) and then store characters in a string. Dynamic arrays can be handled in a similar manner. Various list classes, such as TList<T>, offer a different way—the SetCapacity method, which preallocates the storage.

Memory can also be managed by calling specialized functions, such as GetMem to get a memory block, ReallocMem to change its size, and FreeMem to release (free) it. Or you can use New to allocate memory and Dispose to release it. These two functions will also correctly initialize/clean up records containing managed fields. Alternatively, you can do it manually by calling Initialize and Finalize.

Memory management functions allow you to dynamically allocate and release records. By using these functions, you can use records instead of classes when you create a myriad of small objects. Records are created and initialized faster because they don't have to use inheritance mechanisms as objects do. It is also possible to dynamically allocate generic records (TRecord<T>).

The internal details of the FastMM memory manager—the default Delphi memory manager—are interesting, but most of the time serve no practical purpose. It does, however, help us understand why multithreaded Delphi programs sometimes exhibit bad performance. The reason, surprisingly, lies not in allocating memory but in releasing it. FastMM implements some performance enhancements that help multiple threads allocate memory (for example, create objects) at the same time, but they will have to wait for their turn to have their memory released (objects are destroyed).

Two recent additions to FastMM, contributed by yours truly, help with that. To use any of them, you'll need the latest version from the official repository (https://github.com/pleriche/FastMM4) and not the version that comes with Delphi.

Compiling with the LogLockContention symbol defined enables a special detection mode that helps you find parts of program that are fighting to access the memory manager. You can think of it as a specialized profiler, one that is not interested in execution times, but in memory management.

Alternatively, you can compile your program with the UseReleaseStack symbol defined. This will enable a special mode that minimizes the problem of releasing memory. Everything comes with a price; this solution does its magic by using more memory than standard FastMM.

You could also replace the built-in memory manager, which is a simple matter of calling two functions—GetMemoryManager and SetMemoryManager. One good and tested alternative, written in Delphi and assembler, is ScaleMM (https://github.com/andremussche/scalemm). Another good alternative is Intel's TBBMalloc. It is written in C but can be linked to Delphi by using techniques from Chapter 8, Using External Libraries. The simplest way to use it is to download a compiled version and Delphi wrappers from https://sites.google.com/site/aminer68/intel-tbbmalloc-interfaces-for-delphi-and-delphi-xe-versions-and-freepascal.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.22.73