As for the kernel code, besides the architecture specific code, which is a very small portion (1% to 5%?), all the kernel source code is common to all architectures.
About the binaries:
Actually in most Linux distributions,
vmlinuz is a symbolic link that points to the actual gzipped kernel code; like
vmlinuz-3.16.0-4-amd64. I am sure the OP is talking about the latter, however mentioning the former for the benefit of the reader.
While it is indeed true that ARM code is indeed smaller, even if the kernels were not compressed, the kernel codes in ARM are often custom made, and have far less code activated, than in the Intel counterpart versions (e.g. Intel has a lot of video cards, even if just the modules stubs, while usually the custom ARM kernel only has to deal with the one that is present in the SoC).
In addition comparing already compressed random binary blobs maybe not yield always the true results as per some strange coincidence a bigger binary might become smaller due to some compression optimisation.
So in reality, to compare effectively the binary kernels, you have to compile them with identical options, and keep them uncompressed (or uncompress the resulting
A fair match would be comparing other, non-compressed binaries for instance
/usr/sbin/tcpdump, and furthermore an architecture similar to the one we are trying to match (ARM machines is still largely 32-bits, however there are already a few 64 bits ones)
Needless to say, the same code compiled in ARM will always be (far) smaller because the ARM machine code is a RISC platform code. It has a smaller subset of machine code instructions too, that result in a smaller code. In the other hand, the Intel has a bigger set of instructions, also due to the retro-compatibility inheritance with multiple generations of microprocessors.
The concept of the RISC CPU is an old one, and it is also a very
efficient one. In RISC CPUs you have smaller workloads being run by
each instruction, these instructions are also very often split into
I/O and Memory to further eliminate overhead. This makes for very
efficient use of CPU and memory time, but can also require some bulky
code on the software side to make everything work. When RISC first was
developed, it was the way to go simply because memory and HDD access
was slow. The bulky and complex instructions found in an x86 CPU were
cumbersome on older CPUs and could not keep up with RISC systems.
Nevertheless, the conversation is not that straight enough, as Intel chips are a complex beast nowadays, and deep down the pseudo-CISC layer they have RISC strategies and designs that decode and emulate the Intel opcodes as we know them.
The ARM opcodes are also bulky, compared say to a MIPS, since the ARM is a cheap processor with specialised instructions dedicated to video decoding (around 30% of the processor die is dedicated to them).
As a short exercise, take the tcpdump binary and the four Linux architectures I have access to:
MIPS 32 bits -> 502.4K
ARM 32 bits -> 718K
Intel 32 bits (i386) -> 983K
Intel 64 bits (x86_64) -> 1.1M
So coming back to your original question:
- ARM kernels "grow" less in size because the architecture has less
diversity in the base hardware for a specific distribution.
- However, and much more significant,
they grow less in size because the code produced is more efficient