Delphi: storing data in classes against records, reducing memory usage

I have quite a lot of data to store, read and change in memory when the application is running. The data can be compared with a tree where each node is described by a limited number of lines and integers and has quite a few subelements. Currently, data is stored using classes / objects such as

TRootElement = class fName, fDescription: string; fPos: integer; /// etc end; fDocs: TObjectList; //list of TVariable = class(TRootElement) fClasses: TObjectList; // list of TClass=class(TRootElement) 

currently, the memory consumed by the program is unacceptable, so I'm looking for a solution to limit it.

My question is: will consumption be significantly reduced if I replace the existing architecture based on OOP and objects based on record-based? For example, a shared record might contain:

 TRootElement = record fType: TElemType; // enum: root, variable, class, etc ... fName, fDesc: string; // all the fields used by root elem and it descendants there end; 

Should I replace TList with pointers to next / previous elements? Since I never access list items by index, I always iterate over the entire list, this should not be very difficult to do ... however, I would like to avoid this if not necessary.

Thanks! m

+4
source share
4 answers

Changing the class in a record will reduce memory usage, but the value of savings decreases as the number of fields in the class or record increases. The size difference between the class and the corresponding record is exactly four bytes, which is indicated by the VMT pointer , which the class holds, but which is not in the record. This difference, as a rule, is insignificant if you are considering a compromise: to save four bytes, you refuse inheritance, polymorphism, data hiding and other object-oriented functions. (Some of these can be mitigated using the new Delphi "records" using methods, but if you only have Delphi 2005, you do not have this feature yet.)

In fact, if these four bytes really make a difference for your program, you probably have a big problem to solve. This four-byte savings is erased simply by adding another node to your tree. With a sufficiently large dataset, it does not matter how small you make any node, since you will still not be able to store them in memory. You need to investigate some kind of caching scheme, so only some nodes are stored in memory, and the rest are stored elsewhere, for example, in a file or database.

If you replace your current lists with doubly linked lists of nodes, you are likely to see an increase in memory usage, because now each of your nodes keeps track of its next and previous neighbors, and before TObjectList manages all this on its own.

+14
source

currently, the memory consumed by the program is unacceptable.

What is the meaning of inadmissibility? Do you understand this? What are the facts (number of objects, size of objects, used memory)?

Do you check with FastMM if your program has a memory leak? If this is not the first thing you should do.

If your lists grow frequently, you may have a memory fragmentation problem. Use the list capacity property (if possible). A linked list may help in this situation, but a linked list requires more memory than a TList (if capacity is used wisely). See How to control or visualize delphi application memory fragmentation for more information on how to verify it.

For Delphi <= 2005 it may be useful to replace Borland Memory Manager with FastMM, it is so easy to do.

At least, like Rob, I don’t think changing records will solve your problems.

+2
source

Compared to the vast majority of IDEs, increasing the memory for downloading all PHP5 metadata of only 10 megabytes is actually pretty good.

If this is really worth the effort for you, I would start by merging strings.

Make all the rows in the global table (or dictionary) and point all your rows to it.

You can do it even further, because the language and libraries of PHP 5 are quite static: convert the entire data structure from dynamic to static constants (using records) and all types of index enumerations.

What you could do is make all your string resourcestrings or string constants and see if the Delphi compiler can do literal merging for you.

I just noticed that you are also downloading documentation for all PHP5 stuff. It has a lot of memory. You might want to load them into compressed streams.

+2
source

If you can set string limits, as Cornell says, that really matters. ansistring has some internal overhead as well as additional overhead. However, a shortstring is always allocated, even if not used.

If you are really tightly exchanging memory, making your own allocation for strings more reasonable, especially if the data is relatively immutable. Then just select the large block and put all the lines there with a 16-bit prefix or so.

Less low-level tricks, such as just deduplicating (some of) strings, also save a lot of storage space.

Please note that discussion of the vs class of the Rob class occurs only if you manage to statically create an instance of the class in memory, which you allocate very cheaply, which you probably do not. This is because you can use an array of records. Otherwise, the fact that it is always a reference type causes heapoverhead and -slack (fastmm, 16-byte granularity)

I would recommend not using tstringlist / tlist / tobjectlist, because deleting on very large lists (in millions) can be painful, because deleting / pasting is O (n), and pasting in the middle means shifting half the data. It gets painful somewhere between 20-100k and 1M elements, depending on how your access pattern is.

Using tlist tlists and not letting each tlist get too big is already a good workaround.

When I did this (for an OLAP cluster, when the 2 GB server memory was still $ 2000), at some point I even used the alignment bits in the pointers to store the size class of distributions. I would not recommend this :-)

Of course, a 64-bit version with FPC is also an option. I have the main part of a server above a 32-bit solution, working on a 64-bit version in less than an hour.

+1
source

All Articles