A server app was started on Solaris (Sparc) with JDK 1.3.1 with -server -Xmx16m options. Runtime.totalMemory says 4M. Solaris's "top" command says 37M: PID USERNAME THR PRI NICE SIZE RES STATE TIME CPU COMMAND 22928 root 42 49 0 37M 20M run 0:08 0.54% java If Solaris honors the max heap size of 16m, what makes up the 37M that top show? Heap plus stack + ...? How can I reduce the 37M that top shows? The number in the SIZE column (currently 37M) DOES NOT DECREASE even when my app does does less work. It's a server app; Top's SIZE does not decrease when streaming clients disconnect from my app.
More>>

The correspondence between the java.lang.Runtime memory figures and actual system memory usage is not close. Like most native applications, the Java interpreter never gives back memory it's taken from the system - so you shouldn't expect to see rising and falling numbers here matching what the Java GC is doing.

It is theoretically possible for an application to give back memory with the low-level sbrk() kernel call, but there are practical difficulties - the memory given back must be a contiguous chunk at the high end of the address space. That's virtually impossible without garbage collection (i.e., in most native applications) and also impossible with current implementations of libc's standard allocator (malloc()).

So why doesn't the Java interpreter, which does have GC, give back memory? My conjecture is that this would be vastly more trouble to implement (if even possible) than it's worth. Not to fear: garbage-collected memory is not lost, it's endlessly reused. It's just not returned to the system, where it would be reflected in falling memory usage values.

So, on to the questions:

1) The 37M includes the heap and stack sizes managed by the JVM, plus the overhead of managing those memory pools, plus allocations of non-objects made by native code - in other words, a lot of overhead. It might also (depending on top's behavior) include the shared memory occupied by the JVM's native code itself.

2) There's not much you can do about it. That overhead is the cost of running the Java interpreter above and beyond the heap and stack space for objects and the Java thread stacks.

3) The explanation at the start of this answer should address this question.