5

I'm asking this out of curiosity rather than real need, but can the memory usage of this tiny MSVC++ program be reduced further? Source file on BitBucket.

The program was compiled with "optimize for code size". It creates a message-only window and sets a keyboard hook, showing a tray icon in response to Caps/Num/Scroll Lock key presses.

According to VMMap, the private bytes are allocated as follows:

260 KB: Image
252 KB: Heap
240 KB: Page Table
 24 KB: Stack
 24 KB: Private Data
------
800 KB  TOTAL

Image

The application itself uses only 20 KB of this; the rest is consumed by a dozen of DLLs. Looks like this is as small as it gets.

Heap

The program only allocates about 3 KB of data on the heap: exactly three instances of a certain class. The rest must come from the CRT and/or the standard OS code.

Can this be reduced perhaps? This looks like a prime candidate for savings.

Page Table

The total virtual size of this program is 44 MB, which is about 11k pages. That's 22 bytes per page on average (though presumably a bunch of entries are set aside unused). So this probably can't be reduced any further. Or can it?

Stack and Private Data

Well, those are already insanely small... though I do wonder why they aren't even smaller. The program does not have anywhere near that much private data or stack, I think.

Can you suggest ways of making any of these sections smaller than they already are?


Further findings:

  • a blank no-CRT program uses about 204 KB
  • call to CreateWindow adds 420 KB
  • call to set the keyboard hook adds 156 KB
  • avoiding the use of CRT saves 20 KB
  • the total virtual size increases in a similar manner
  • not using the CRT saves quite a bit in EXE size: from 54 KB down to 18 KB, 12 of which are resources.

So it looks like most of this memory is consumed by Windows API, which seems to preclude significant further reductions, unless one can figure out a way to make the hook / tray icons work without creating a window (this program already ignores all messages anyway).

Roman Starkov
  • 59,298
  • 38
  • 251
  • 324
  • 1
    You could try to change the default heap size in VS: http://msdn.microsoft.com/en-us/library/f90ybzkh(v=vs.80).aspx to see if that reduce the size. – Lucky Luke Jan 13 '12 at 18:33
  • Regarding close votes: curious to hear your reasoning. – Roman Starkov Jan 13 '12 at 19:34
  • I’m really curious too. What the heck is off-topic about this? – Timwi Jan 13 '12 at 21:50
  • This question seems ambiguous or ill-defined until you dive into what private bytes actually means. – MSN Jan 13 '12 at 22:40
  • It might be off-topic in that "improve working code" sounds more appropriate for a [Code Review](http://codereview.stackexchange.com/) question. My rationale would be the sort of answers it attracts – a list of suggestions rather than a definite answer pinpointing a memory use problem. So, not a "this is not a programming question" off-topic vote, but a "there's a better place for this flavour of programming question" one. (I'm speaking in hypotheticals because I haven't cast a close vote.) – millimoose Jan 13 '12 at 22:52
  • 1
    @MSN I'm not sure if that's a criticism or a comment :) "Private bytes" is a very specific term; not knowing the exact meaning doesn't make the _question_ ambiguous. – Roman Starkov Jan 13 '12 at 23:16

4 Answers4

3

It's possible to completely omit the C runtime library by relying on APIs provided by the OS (which are in DLLs you're already mapping into your process) or by implementing them yourself.

It's generally not worth it, unless you're already making minimal use of the language's runtime library. It also makes your application even less portable.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • 2
    AFAICT, this application isn't using the C or C++ standard library AT ALL. So `/NODEFAULTLIBS` and `/ENTRYPOINT:WinMain` and call `GetCommandLine` instead of using the `WinMain` arguments, and it should get lots smaller. – Ben Voigt Jan 13 '12 at 23:02
  • I am making minimal use of the CRT: I don't even rely on destructors being called (though I'm somewhat unsure if that's a CRT-provided feature). I wonder how much CRT functionality I end up using at all. Do you have more specific examples or links about how to omit the CRT in MSVC++? – Roman Starkov Jan 13 '12 at 23:18
  • @romkyns: I made the few necessary changes: http://pastebin.com/WhAQUnAb But I think I broke something along the way, it compiles, links, and runs, but no tray icons appear. – Ben Voigt Jan 13 '12 at 23:21
  • @romkyns: Also, to answer your question, destructor calls are the CRT's responsibility in most cases. Global and function-static variables (and their constructor calls too), dynamic allocation, and unwind during exception all require the CRT to call destructors. Local variables during non-exceptional exit and class members will be destroyed without help from the CRT. – Ben Voigt Jan 13 '12 at 23:27
  • @romkyns: That file works as-is with the x64 compiler. For the x86 (32-bit) compiler, you have to add `memcpy` as shown here: http://stackoverflow.com/a/2945619/103167 – Ben Voigt Jan 13 '12 at 23:38
  • This is not a great answer for C++. I misread the tag and thought it was C. The C++ RTL will run destructors for globals and statics, and exception handling probably pulls in library code for stack unwinding. – Adrian McCarthy Jan 14 '12 at 00:33
  • This was the only thing that has made any difference yet (albeit a fairly small one). Thanks for the idea and for your other answer about `memset`. This project doesn't really use the CRT much, despite being compiled as C++. Also, kudos @BenVoigt for the specific details and the memset tip. – Roman Starkov Jan 16 '12 at 18:06
2

The "Process Environment Block" contains a copy of all environment variables.

If you don't inherit any environment (i.e. the parent process spawned you with a clean environment) then that might yield a noticeable decrease, relative to the total memory usage you're looking at now.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I understand that I have no control over this; only the parent process can change this? I could respawn myself without the environment, I guess, or is there an easier way to do this? – Roman Starkov Jan 16 '12 at 16:18
  • @romkyns: You can edit your own environment, but I don't think that will shrink the PEB. So respawning with an empty environment would be the solution there. – Ben Voigt Jan 16 '12 at 18:52
1

From this answer, private bytes is a measure of memory either explicitly committed or marked as MEM_PRIVATE or executable pages that have been written to. So, if you dynamically allocate storage instead of using global variables (including function local statics), you should be able to reduce your private bytes usage, although you may increase your overall heap usage.

Community
  • 1
  • 1
MSN
  • 53,214
  • 7
  • 75
  • 105
  • 1
    Normal heap allocations count towards private bytes, so I don't see how this would help. – Roman Starkov Jan 13 '12 at 23:21
  • @romkyns, that's why I said "although you may increase your overall heap usage". I think VMMap splits out heap usage from private bytes when it can determine that the private byte page came from a heap. – MSN Jan 13 '12 at 23:54
0

You can use "pragma pack(1)" to garantee that no extra space will be alocated between the members' memory space.

http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx

Renan Greinert
  • 3,376
  • 3
  • 19
  • 29
  • 1
    This is unlikely to have any noticeable impact: the program only defines one data structure and only three instances of it are created. – James McNellis Jan 13 '12 at 23:55