Solved

TList of records - memory use

Posted on 2004-08-31
13
537 Views
Last Modified: 2008-02-01
Ok, this one most likely will not have an answer in code but i thought i would ask anyway - got to learn somehow and the books i have don't mention anything of use.

Question:  If i have a TList that is used to hold records, is there a way to find out the total memory in bytes used by all of the records in the TList?

0
Comment
Question by:foxjax
  • 8
  • 3
  • 2
13 Comments
 
LVL 4

Accepted Solution

by:
Evarest earned 250 total points
ID: 11940477
Actually this is a more difficult question than you imagine...

The problem lays with the record themselves. In my experience, they're being handled quite oddly (however this odd behaviour is entirely logic in the end). For example:

TMyRec = record
  Name: string;
  Item: integer;
  Period: string;
end;

As this record contains strings which can have different lengths, the memoryallocation will be different if you declare it like follows:

TMyRec = record
  Item: integer;
  Name: string;
  Period: string;
end;

The problem is that Delphi needs to be able to allocate enough memory to place enough reference data to each item in the record. The Integer will be placed in the record's place of the memory, the string will be referenced. This means that the actual string can reside in a different address of your memory, with only a pointer in the record's space.

All this I didn't perceive from some fancy book. It's only hands-on experience, as I once needed to allocate the memory myself.

IMPORTANT: in the latter text, i referred to space in memory as the actual space taken by the entire record. NOT the reference alone, which can easily be examined by calling SizeOf(TMyRec);

When you have the following record:

TMyRec = record
  Item: byte;
  Name: string[250];
  Period: string[250];
end;

This record is much easier to examine: just call sizeof(TMyRec) to get as answer 503 bytes. I might be that you notice that byte = 1 byte and 250*2=500 bytes. Thus normally the size would be 501 bytes. The reason is that the shortstrings always contain x+1 bytes where x: string[x]. These are null-terminated strings.

Conclusion:
You can esily derive the memoryspace of a record by using sizeof(TRecord). However take care if the record contains unterminated strings!

Hope to help,
Evarest
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 11940485
not so easy to calculate

in simple

each entry in the list = 4 bytes
plus the size of your record
plus the tlist-size itself

but if you have strings in your record,
then it will be become complicated, because
each same string is only once in memory
associated with a reference counter

meikl ;-)
0
 

Author Comment

by:foxjax
ID: 11940571
Evarest:  What if i changed the record structure to something like:

TMyRec = record
 Item: integer;                                      <== why the change to "byte" above?
 Name: array [0..4095] of char;
 Period: array [0..1023] of char;
end;

Would that make it easier?

meikl :

I see what you mean by "same string is only once in memory" - i assume delphi just puts a pointer into the place of the string since it already has the string in memory.  Sheesh, makes things a lot more complicated on the poor old developer.
0
Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 27

Assisted Solution

by:kretzschmar
kretzschmar earned 250 total points
ID: 11940626
TMyRec = record
 Item: integer;                            //4 Bytes          
 Name: array [0..4095] of char;    //4096 Bytes
 Period: array [0..1023] of char;   //1024 Bytes
end;

should be 5124 bytes total (calculated by head), if no alignment is issued

>i assume delphi just puts a pointer into the place
yep, but only if the definiton is unlimited (not by string[100])

meikl ;-)

0
 
LVL 4

Expert Comment

by:Evarest
ID: 11940705
>i assume delphi just puts a pointer into the place
yep, but only if the definiton is unlimited (not by string[100])

of course, as if you're using a null-terminated string, Delphi doesn't have need of placing it's contents somewhere else in the memory.
array [0..4095] of char will also place everything on the same place, but doesn't need a #0 terminate.


TMyRec = record
 Item: integer;                                      <== why the change to "byte" above?
 Name: array [0..4095] of char;
 Period: array [0..1023] of char;
end;

I had no reason to change it to byte, but just to give a different example.

[QUOTE]
I see what you mean by "same string is only once in memory" - i assume delphi just puts a pointer into the place of the string since it already has the string in memory.  Sheesh, makes things a lot more complicated on the poor old developer.
[/QUOTE]

This sheds light on the fact that you will have to take care that you free your memory correctly! Just calling

var
 MyRec: ^TMyRec;
begin
 dispose(MyRec);

with MyRec thus a Pointer, will NOT free all memory if the record contains strings.

Finalize(PMyRec(MyRec)^);

thus a record as parameter will free the memory. See my example in your other post for more info...

Evarest
0
 

Author Comment

by:foxjax
ID: 11940707
So with defining limits by using array [0..4095] of char, etc i can then get a good approximation of the total memory used by the records?
0
 

Author Comment

by:foxjax
ID: 11940818
seems sizeof always returns 4 for me - guess i am getting the size of the 4 byte pointer instead of the record in the TList
0
 

Author Comment

by:foxjax
ID: 11940881
oops - my mistake - got it now.
0
 

Author Comment

by:foxjax
ID: 11940946
One final point before i close this question:

I assume that to get a realistic approximation of memory used it would be

sizeof(<record>) * <number of records>) + SizeOf(<TList>)* <number of records>
0
 
LVL 4

Expert Comment

by:Evarest
ID: 11941111
"So with defining limits by using array [0..4095] of char, etc i can then get a good approximation of the total memory used by the records?"

Yep

"sizeof(<record>) * <number of records>) + SizeOf(<TList>)* <number of records>"
sizeof(<record>) * <number of records> + SizeOf(<TList>)

is better i guess, i'm not entirely sure though, never done that. It's only logic as you have a TList (thus the definition in the memory) and a lot of record behind eachother (which gives sizeof(<record>) * <number of records>)...

Greetings,
Evarest
0
 

Author Comment

by:foxjax
ID: 11941178
the reason i did SizeOf(<TList>)* <number of records> is that SizeOf(<TList>) always returns 4 (??) and since i realized that the TList is full of 4 byte pointers to records,  i added *<number of records> to allow for the memory used by the 4 bytes per record in the TList.

Make sense?

0
 

Author Comment

by:foxjax
ID: 11941197
I am going to split the points between the both of you - i raised them to 500 so i can give the original 250 to each of you.  I hope you both agree that it is fair.
0
 

Author Comment

by:foxjax
ID: 11941773
Thanks again guys - i found that quiet informative
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Firemonkey DbLookupComboBox equivalent ? 2 54
Tidtcpserver listening on multiports? 1 35
Tvertscrollbox like a whatsapp layout delete messages 1 23
MS Access from Delphi 31 59
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

790 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question