Proper type specialization has its downsides in compile time and binary sizing. Ideally you would have the option of doing one or the other depending on your situation.
Not if done correctly -- for a JITted language the IL does not increase in size for generic types as the IL still only has a single version (with the type parameters). The JIT can share the code for the majority of Object/Reference instantiations (strictly it could share all object code if it put appropriate type metadata into the in memory class representation).
For value types you do need different copies for the various sizes of type parameter, but even then your heap overhead is reduced because you no longer need to box every value. E.g. you no longer need to make an object to wrap an int. So i suspect on balance you reduce the total space requirements.
FWIW, this is exactly how .NET does this. Generic instantiations are shared between all reference types (at runtime, you can sometimes see this leaking into visible abstractions in form of System.__Canon pseudo-type in call stacks etc), but separate instantiations are produced for every value type.