I am working on a C++ program and the compiled object code from a single 1200-line file (which initializes a rather complex state machine) comes out to nearly a megabyte. What could be making the file so large? Is there a way I can find what takes space inside the object file?
There can be several reasons when object files are bigger than they have to be at minimum:
- statically including dependent libraries
- building with debug information
- building with profiling information
- creating (extremely) complex data structures using templates (maybe recursive boost-structures)
- not turning on optimizing flags while compiling (saves not that much and can cause difficulties if used too extremely)
At first I suggest to check if you're building with debug information, this causes the most bloat in my experience.
(I'm assuming you've got optimisations and dead code stripping turned on).
Turn on your linker's "generate map file" option and examine the output.
Common culprits are macros/templates that produce large amounts of code, and large global objects.
Possibly some template instantiations (especially the std::iostream
s), and maybe extensive inlining (i.e. classes which are fully defined in a header). However, what's the problem with a 1-megabyte object file in the first place? During linking, it might very well result in a tiny binary. I got a project here with 20 MiB of object files which gets linked into a 700 KiB binary for example.
Update: Could be also some large static array/object. Besides that, with MSVC++ and GCC, you can look at the generated assembly for a file, which can give you some hints (with GCC, it's g++ -S foo.cpp
, for MSVC++, it's '/FAs'). Either you will see a lot of template instances, then these are the reason. If not, it's the object size of static
objects.
Another possible reason is Link-Time Code Generation, a VC++ option. This moves the backend of the compiler into the linker. This allows for better optimizations, but the object file now has to contain all internal datastructures usually passed between front- and backend.
One good bet would also be to have a look at the possibilities mentioned at Tool to analyze size of ELF sections and symbol e.g.:
nm -C --print-size --size-sort --radix=d tst.o
size -A -d tst.o | sort -k2 -n
I've seen cases where debug symbols are MASSIVE in C++, e.g. 30x larger than the rest of the binary, so this is definitely one of the things to look out for, the above size
command would tip you off immediately due to huge debug related sections, and you can double check by stripping the binary with strip
or g++ -s
.
Another thing to look out for is if you can save some space/time with explicit template instantiation: Explicit template instantiation - when is it used? The "How to quickly analyze your build to see if it would gain a lot from template instantiation" section of that answer also contains a methodology to find duplicate objects across object files in a large (C++) project.
You can by adding the compilation flags -flto -Wl,-allow-multiple-definition
and you can add -fuse-linker-plugin
. -Wa,-mbig-obj
do not work on x86/32bits architecture (only x64)
Here's a macro I use to see compile time values:
template <size_t N> struct compile_time_number { private: typedef int check; };
#define compiler_check_number(N) ((compile_time_number< N >::check)0)
Then go happy at compile time to see what symbols are taking up space.
Edit: Since no one seems to understand this, I'll clarify: the way to use this is to add compiler_check_number(sizeof(<insert struct or global variable here>))
. The compiler will spit out the size of the variable or struct as a compile time error. Very rarely is code the reason for a huge object file.
I use this all the time to see how big things are without having to run a debugger.
© 2022 - 2024 — McMap. All rights reserved.