A lot of Java is optimized for this, and it would take a fair bit of work to make a JVM (and compiler!) implementation that changed the behavior pervasively.
Java assumes memory is cheap at many levels. And usually, it's right.
I would say it's usually wrong. Imagine how much ram you'd need if all of your GUI apps were on the JVM. Imagine how much ram you'd need if '$ cat blah.txt | grep "something" | uniq | sort' were all JVM processes. Etc, etc, etc.
It seems to only be right for long lived server side processes that have enough load to make it a benefit.
The JVM is not The Unix Way. You have to do things differently - and in Java-land, they do.
It's not really my thing either, but it's not as bad as you'd think if you just pretend we're mapping all our existing Unix stuff, unchanged, into Java.
From my experience at University, the JVM uses an indirect method of accessing and storing objects. So each reference to an object is effectively a handle, hence as big as a pointer. It points to a table that contains the actual pointer to the object in memory (or something to that effect), so that the garbage collector can move the object in memory.
Therefore an object that just has a single integer will require 2 pointers and an integers worth of memory (at least). Any less than that and it would be garbage collected since there are no live references in the code to the object.
Garbage collection isn't free.
In 64-bit VMs without a very large maximum heap size, the JVM usually uses "compressed" pointers, too, so 32-bit values can, in practice, address 32GB of data. Intel CPUs have addressing modes that work quite well with this. See: http://wikis.sun.com/display/HotSpotInternals/CompressedOops
Garbage collection isn’t free, but it’s getting pretty good.
edit: keep in mind this memory includes your app server, in my case I was using jetty.