1

I am trying to find size of built-in classes for an example TControl,TWinControl etc. Tried with InstanceSize() which in turn might not add size of few types considering them as references.

Found an interesting stack-overflow thread talking about TMemoryStream to find out class size:Getting the Size of a Class or Object in the same format as a File Size? couldn't get much info on how to use TMemoryStream to figure out class size, can I get assistance regarding this?

1 Answer 1

6

You are right: TObject.InstanceSize returns the instance size in memory. Not the nested fields.

If you want to compute the "size" of the class instance in memory, then the value will never match what any streaming process would do.

I mean, if you serialize your class instance into a TStream, the size will depend on the actual serialization. Not the total memory used size. Most serialization engines will only serialize the published properties, not the public and not the nested protected fields. And if you serialize as JSON, or as DFM binary, or as DFM text, or as ProtoBuf or as our mORMot binary layout, you will have diverse values, which won't match the actual RAM consumption.

The situation is even worth for nested reference types, like string or dynamic arrays. They use reference counting, so a single string instance, if reused in several properties/variables, will just consume its length once for all the occurrences... And what about nested objects, which may be reused between instances?

So there is no simple way to compute how much "memory" a class instance consumes. What you can do is write your own function, with an "estimate" of the consumed memory. Something like

 function TMyObject.ConsumedBytes: integer;
 begin
   result := InstanceSize +
     length(fName) * SizeOf(char) +
     length(fFirstName) * SizeOf(char) +
     length(fAddress) * SizeOf(char);
 end;

And even this would be considered as an estimation, not how much RAM was consumed. For instance, some types like string do have an header before the text (including length, refcount and codepage), and the memory manager itself would always reserve a bit more than what is exactly needed, for low-level reasons of optimization.

I guess you need to refine what is your goal. If it is to check for memory usage, then you need to learn a bit more about how Delphi uses its memory for its low level types, and how the heap memory manager reserves memory areas from the Operating System.

Sign up to request clarification or add additional context in comments.

7 Comments

This is the right answer. But you need to multiply your string lengths by SizeOf(Char).
@AndreasRejbrand You are right: I have fixed it.
Thanks @ArnaudBouchez,am from C++ background and bit new to Delphi.If InstanceSize could do what sizeof does in C/C++ that is more than enough. Though I had made structures to match with returned InstanceSize ,application was still not happy about size.
Technically, it should be (Length + 1)*SizeOf(Char) + StringHeaderSize. StringHeaderSize being 12 bytes for 32 bits application and 16 for 64 bits application (as of Seattle). Codepage(2) + SizeofElement(2) + RefCount(4) + Length(4) + (64bitsonly)padding(4). Length+1 is because string always reserve (at least) 1 additionnal character and make it null for PChar compatibility purpose.
Although you are right in principle, @KenBourassa, we are still fundamentally only doing an estimate, so it is probably "good enough" as it is. If you want to be "exact", you first need to define more precisely what the number should be, and then you need a rather complicated implementation. For instance, you must check if two string fields are pointing to the same heap object or not.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.