Jump to content
Kryvich

RTTI and EXE file size: how to shrink your executable 2 times

Recommended Posts

As you know, modern Delphi versions add the RTTI information to the executable file. RTTI gives you the opportunity to do incredible things in your application. But it is not always necessary. You can disable RTTI in your application by adding the following lines to each unit:

{$WEAKLINKRTTI ON}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}

But to completely disable RTTI, you need to add these lines to used RTL units too, and rebuild the project.

 

How much will the size of the executable file decrease? Well, I checked it on small utilities from the Delphi Localizer project, and here is the result:

  • kdlscan.exe was 742400 bytes, now 360448 bytes, -51%
  • lngupdate.exe was 727040 bytes, now 282112 bytes, -61% (!!!)

The smaller size of an executable file means that the file is read twice as fast from disk. In addition, the processor is more likely to be able to fully fit your utility into its cache. You can give other reasons why this makes sense.

Share this post


Link to post

Aren't there compiler settings you could set so the 'Release' build would exclude RTTI, so you could still have it in the 'Debug' build?

Share this post


Link to post

@stijnsanders I do not know such special settings. But you can use conditional compiler directives to leave RTTI for the Debug build:

{$IFDEF RELEASE}
{$WEAKLINKRTTI ON}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
{$ENDIF}

 

Edited by Kryvich

Share this post


Link to post
1 hour ago, Kryvich said:

As you know, modern Delphi versions add the RTTI information to the executable file. RTTI gives you the opportunity to do incredible things in your application. But it is not always necessary. You can disable RTTI in your application by adding the following lines to each unit:


{$WEAKLINKRTTI ON}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}

But to completely disable RTTI, you need to add these lines to used RTL units too, and rebuild the project.

 

How much will the size of the executable file decrease? Well, I checked it on small utilities from the Delphi Localizer project, and here is the result:

  • kdlscan.exe was 742400 bytes, now 360448 bytes, -51%
  • lngupdate.exe was 727040 bytes, now 282112 bytes, -61% (!!!)

The smaller size of an executable file means that the file is read twice as fast from disk. In addition, the processor is more likely to be able to fully fit your utility into its cache. You can give other reasons why this makes sense.

Not really. The file is mapped into memory and then read from the disk when the virtual memory system encounters page faults. So if you don't use the RTTI it will never be read. 

 

Don't theorise about performance. Measure. 

Share this post


Link to post

@David Heffernan How you think: is RTTI information concentrated in one place of an executable file, or scattered around it? Open any EXE file and find the answer. I would prefer that the RTTI information be in a separate segment (resource) of the EXE file, and preferably in a separate file. But you are right about performance: it is better to test, and then draw conclusions.

Edited by Kryvich

Share this post


Link to post
14 hours ago, Kryvich said:

@David Heffernan How you think: is RTTI information concentrated in one place of an executable file, or scattered around it? Open any EXE file and find the answer. I would prefer that the RTTI information be in a separate segment (resource) of the EXE file, and preferably in a separate file. But you are right about performance: it is better to test, and then draw conclusions.

Perhaps I'm guilty of making assumptions. I presumed the RTTI was in a resource. 

 

Still always best to measure. 

 

FWIW I disable RTTI when I don't need it. 

Edited by David Heffernan

Share this post


Link to post

I use RTTI extensively, so turning it off would have undesirable effects,

I wish there was a simpler way to enable/disable it for specific inheritance trees, though.

Share this post


Link to post

I found a few more units with RTTI and was able to further reduce the utilities from the Localizer project. Now the numbers are:

  • kdlscan.exe was 742 400 bytes, now 355 840 bytes, -52%
  • lngupdate.exe was 727 040 bytes, now 277 504 bytes, -62%

I also tested one of my applications with and without RTTI. Application: Windows 32-bit utility, VCL, memory tables, RichEdit components, string processing. I measured only the speed of text processing, not the speed of launching the application. I have to say, in my case there is no gain in performance after the removal of RTTI.

Test Application Executable File Size, bytes Processing time, best run, s
RTTI enabled 4 777 472 62
RTTI disabled 3 300 864 61
Difference, % -31% -2%

Probably, the tested program is too small, and can fit in the processor's cache entirely in both cases.

Edited by Kryvich

Share this post


Link to post

Question:  I'm not using RTTI, AFAIK.  If somehow, due to a mistake on my part, RTTI is needed. Will that show up as a run-time error, or compile-time error?

 

Share this post


Link to post

Sorry to ask such a beginners questions, but I am unfamilar with that method.

If i want to reduce filesize I do use Executable Packer like U.P.X..

 

So my questions would be:

Beginning with wich Delphi Version does your approach to reduce filesize at linking work?

When you say "add that to used units" do you mean all (my own units like "Unit1.pas" plus original RTL sources like "Windows.pas") ?

 

My next question would be, if i need to add that to all RTL units, how do i compile them? (i never tweaked original units yet)

I did tried that:

Open existing project

Open used units to add the {$IFDEF RELEASE} variant

At a undefined point, my IDE crash during edit those originals

(i did tried with Delphi 5 and Delphi 2010)

 

Exists a instruction for dummies like me?

Share this post


Link to post
5 hours ago, Stefan Glienke said:

The R in RTTI is for runtime - now please guess 😉

Hi, Stefan,  

 

I don’t like guessing on things as important as this. If I guess wrong, the consequences shipping a defective product which fails in the field are too great. 

 

I assume that what you intended to communicate  was that errors from missing RTTI info will be flagged at compilation time, not runtime.  Is that correct?

Edited by Tom F

Share this post


Link to post

Your question shows your lack of knowledge on the topic (I don't mean that in any form negative) so I suggest you should not mess with it.

RTTI is queried with code that executes at runtime and thus can only cause errors at runtime.

 

And even if you in your code don't explicitly make use of RTTI that does not mean that any other part might not do it (either third party or even RTL).

Want to serialize some object to JSON and use System.Json - ohh, will not work if you did disable RTTI (just one example).

 

So unless you really have a problem because of binary size (and no, we are most likely not in a 64k demo scene competition here) then apply the first rule of optimization by Michael A. Jackson: "Don't do it."

  • Like 3

Share this post


Link to post

@KodeZwerg First, read the remark from Stefan Glienke above.

Quote

Beginning with wich Delphi Version does your approach to reduce filesize at linking work?

Advanced RTTI available in Delphi since version 2010. So applications compiled in Delphi 5 do not contain it.

Quote

When you say "add that to used units" do you mean all (my own units like "Unit1.pas" plus original RTL sources like "Windows.pas") ?

Yes it is. You can find the complete list of units contained in your application in the PACKAGEINFO resource in your executable file. Use a resource viewer to access it, for ex. Restorator.

Quote

if i need to add that to all RTL units, how do i compile them?

There is BuildWinRTL.dproj in source\rtl. You can copy the RTL folder to your work folder, inject the code to disable RTTI in every used PAS file, check Search path and Unit output directory (instead of "$(BDSCOMMONDIR)\lib\$(Platform)" you can set "..\lib\$(Platform)"), check build configuration (Release, Win32) and rebuild the BuildWinRTL project. You'll find DCU files in the lib\Win32 folder.

 

In case you use any other VCL units and third-party libraries you should inject the code in every PAS file of these libraries too, to remove RTTI completely. Copy the used VCL units to a separate folder in your working folder, do not modify the files in the Source folder of Delphi.

 

Make sure your application’s search path for the Release build configuration points to the recompiled DCU files of RTL, and to modified PAS files of VCL. Now you are ready to compile your application without RTTI.

Edited by Kryvich
  • Thanks 1

Share this post


Link to post

I appreciate your help!

Your edit cleared the mist i saw, thankyou!

The rest i sure will figure out, you lead me on the way to do and play with 😄

  • Like 1

Share this post


Link to post
2 hours ago, Stefan Glienke said:

So unless you really have a problem because of binary size (and no, we are most likely not in a 64k demo scene competition here) then apply the first rule of optimization by Michael A. Jackson: "Don't do it."

Once I make a utility that the user ran from a network drive. Moreover, it was launched many times during the day to process incoming documents. Then they asked me to make the EXE file as small as possible to speed up the processing. Removing RTTI from the executable file has greatly accelerated the workflow.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×