1

In Delphi 10.4, I have a record that I use like this in a TList (System.Generics.Collections):

uses
    System.Generics.Collections;

type
    TSomething = record
        Name: String;
        Foo: String;
        Bar: String;
        Group: String;
        Flag1: Boolean;
        Flag2: Boolean;
        Flag3: Boolean;
        Flag4: Boolean;
        Flag5: Boolean;
    end;

    PTSomething = ^TSomething;


//Simplified code for readability...


var
    Something: TSomething;
    MyList := TList<TSomething>;
    lRecP: PTSomething;

MyList := TList<TSomething>.Create;

while ACondition do
begin
    Something.Name := 'Something';
    //Fill the rest of the record
    MyList.Add(Something); //Add is done in a while loop which result around 1000 items in MyList
end;

//Later...
for i := 0 to MyList.Count - 1 do
begin
    if ACondition then
    begin
        lRecP := @MyList.List[i];
        lRecP.Name := 'Modified'; //Items can be modified but never deleted
    end;
end;

//Later...
MyList.Free;

Is my code prone to memory fragmentation? I have about 1000 records in my list that I will iterate through and maybe modify a string off the record once per record.

Would there be a better way to do what I want to do?

AlexV
  • 22,658
  • 18
  • 85
  • 122
  • Answer in general depends on how the list is populated and how items are inserted/deleted during its lifetime. Of course in the code you present you don't need to use a list because there is only one item. – David Heffernan Feb 10 '22 at 06:58
  • @David Heffernan I updated my question to be closer than my actual flow. I add records to the list in a loop (resulting in about 1000 'add') and later I iterate the list and update a string based on a condition but never remove any item from the list. Then I free the list. – AlexV Feb 10 '22 at 13:21
  • I guess you aren't using string literals, so there presumably is heap alloc for new strings. But, anyway, nothing here jumps out as a problem. Do you experience any problems? – David Heffernan Feb 10 '22 at 14:03
  • @David Heffernan No the string in the `Add` are results from a COM object query and in the modify it's a string replace ("translating" an environment variable into the actual value if present in the string). I don't have any problems, I'm just trying to learn more advanced memory management that I never dealt with in the past. – AlexV Feb 10 '22 at 14:20
  • I don't think that there is much scope for learning with the usage scenario described here, it seems pretty tame. – David Heffernan Feb 10 '22 at 14:22
  • @David Heffernan Good. My interrogation spawned after reading [this question](https://stackoverflow.com/questions/5797368/delphi-tlist-of-records) but I think it applied to older Delphi versions... – AlexV Feb 10 '22 at 14:27

2 Answers2

1

Records lie in intrinsic dynamic array of TSomething. This array will be reallocated when you add new records and expanding is required. Memory manager cares about memory allocation, deallocation, it tries to minimize fragmentation. For list size of 1000 fragmentation should be negligible. Dynamic array capacity changes rarely to avoid expensive operations of reallocation and to diminish fragmentation (more info in SilverWarior comment)

You records contain strings. Strings are really pointers, and strings bodies are in another place of memory. Again - memory manager cares about string allocation/deallocation, it does this work well (applications with instant creation, treatment and deallocation of millions of strings work 24/7 many years).

So frequent changing of strings does not affect on the list body (intrinsic array) (until you add new records/ delete existing ones), and unlikely can cause memory fragmentation.

MBo
  • 77,366
  • 5
  • 53
  • 86
  • _I don't see a reason for PTSomething = ^TSomething; usage._ The variable declaration _lRecP: PTSomething;_ uses it. – HeartWare Feb 10 '22 at 06:31
  • @HeartWare I see, but that usage has no benefits from pointer kind of variable, so I proposed it is relict of old TList or pointer-based implementation of dynamic arrays before D4 – MBo Feb 10 '22 at 06:38
  • See my reply below (I needed to supply code example, so couldn't do it in a comment). – HeartWare Feb 10 '22 at 06:48
  • Example is OK, but it describes specific peculiarities. What's relation to current situation? `TList` gives `TSomething` instances, there is no need in type casting (at least in given code piece), as old TList required – MBo Feb 10 '22 at 06:52
  • @HeartWare Ahh... It's a reason, My fault, forgot about record copying. – MBo Feb 10 '22 at 07:03
  • @HeartWare In discussion I missed usage of `MyList.List[0]` that allows direct access to fields – MBo Feb 10 '22 at 07:07
  • Me, too - that's why I removed my comment about the COPYing of records from lists. – HeartWare Feb 10 '22 at 07:15
  • 1
    @MBo You should also mention that when dynamic array that stores list objects is expanded it is rarely expanded for the size of just one item bit instead it gets expanded for the size of several items at once. This helps reducing the number of needed memory reallocations if the array cant be resized at current place which also helps reducing the memory fragmentation. By default initially when the array is small its size is being doubled each time it is expanded. But once it reaches certain size it gets expanded in fixed chunk sizes. – SilverWarior Feb 10 '22 at 10:31
  • I updated the code sample in my question to reflect more the actual flow I have in my app. – AlexV Feb 10 '22 at 13:36
  • 1
    @AlexV Answer is still valid. Also you don't need to use pointer variable PTSomething because MyList.List gives direct access to record fields (until you have specific plans for pointer variable) – MBo Feb 10 '22 at 13:39
  • @MBo Yeah in my code I changed that already, thank you! – AlexV Feb 10 '22 at 16:01
0

This is not an Answer to your Code. I don´t know if Fragmentation happens. In my experience it is dependent on other things happening in parallel or over time. If your Application has Issues like "E Out Of Memory" after running several days, then its time to look at it.

I Would suggest having a look at FastMM. Using its FastMMUsageTracker Memory Fragmentation Map over FastMM

For me it was a big help. I had Problems in a Service, but i cant remember where i read about Memory Exhaustion. In FastMM or Mad Except? Sorry i can´t remember. It was a Article explaining why Fragmention happens over time.