Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi: storing data in classes vs records, memory usage reduction

I have quite a lot of data to store, read and modify in memory while the application works. The data could be compared to a tree, where each node is described by limited number of strings and integers, and has quite a lot of subelements. Currently the data is stored using classes/objects, like

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, thus I'm looking for the solution to limit it.

My question is: will the consumption be significantly reduced if I replace current, OOP and Objects based architecture with one based on records? For example, the general record could contain:

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

Should I replace TList with pointers to next / previous elements? Since I'm never accessing the elements of list by index, I'm always looping through the whole list, it shouldn't be really hard to do... however I'd like to avoid it if not necessary.

Thanks! m.

like image 420
migajek Avatar asked Nov 30 '22 11:11

migajek


2 Answers

Changing a class into a record will reduce memory usage, but the significance of the savings decreases as the number of fields in the class or record increases. The size difference between a class and the corresponding record is exactly four bytes, which accounts for the VMT pointer that a class holds but which is absent from a record. That difference is usually negligible when you consider the trade-off: To save four bytes, you give up inheritance, polymorphism, data-hiding, and other object-oriented features. (Some of that might be mitigated with Delphi's new "records with methods," but if you only have Delphi 2005, you don't have that feature yet.)

In fact, if those four bytes really make the difference for your program, then you probably have a bigger problem to solve. That four-byte savings is wiped away simply by adding another node to your tree. With a large enough dataset, it won't matter how small you make any one node since you won't be able to keep them all in memory anyway. You'd need to investigate some kind of caching scheme, so only some nodes are kept in memory and the rest are kept elsewhere, such as in a file or a database.

If you replace your current lists with doubly linked lists of nodes, you'll probably see your memory use increase because now each of your nodes is keeping track of its next and previous neighbors whereas before the TObjectList was managing all that itself.

like image 51
Rob Kennedy Avatar answered Dec 24 '22 00:12

Rob Kennedy


currently the memory consumed by the program is unacceptable

What is the meaning of unacceptable? Have you mesure it? What are the facts (number of objets, size of objects, used memory)?

Have you check with FastMM if your programm has a memory leak? If not this is the first think you should do.

If your lists often growing then perhaps you have a problem with memory fragmentation. Use the capacity property of the list (if possible). In this situation a linked list can help but a linked list needs more memory than TList (if capacity is used sensible). See How to monitor or visualize memory fragmentation of a delphi application for more Information how to check it.

For Delphi <= 2005 it can be helpfull to replace the Borland Memory Manager with FastMM it is so easy todo.

At least, like Rob, I don't think that a change to records solve your problems.

like image 21
Heinz Z. Avatar answered Dec 24 '22 01:12

Heinz Z.