JDK 8
-XX:+PrintGCDetails
The heap layout and usage will be printed at VM exit:
PSYoungGen total 443904K, used 283177K [0x00000000dcc00000, 0x00000000f7f00000, 0x0000000100000000)
eden space 442368K, 63% used [0x00000000dcc00000,0x00000000ee07a6f8,0x00000000f7c00000)
from space 1536K, 4% used [0x00000000f7d80000,0x00000000f7d90000,0x00000000f7f00000)
to space 1536K, 0% used [0x00000000f7c00000,0x00000000f7c00000,0x00000000f7d80000)
ParOldGen total 72704K, used 980K [0x0000000096400000, 0x000000009ab00000, 0x00000000dcc00000)
object space 72704K, 1% used [0x0000000096400000,0x00000000964f5060,0x000000009ab00000)
Metaspace used 4568K, capacity 4718K, committed 4992K, reserved 1056768K
class space used 472K, capacity 532K, committed 640K, reserved 1048576K
JDK 9+
-Xlog:gc+heap+exit
[9.405s][info][gc,heap,exit] garbage-first heap total 276480K, used 149668K [0x0000000700000000, 0x0000000800000000)
[9.405s][info][gc,heap,exit] region size 1024K, 147 young (150528K), 1 survivors (1024K)
[9.405s][info][gc,heap,exit] Metaspace used 6335K, capacity 6395K, committed 6784K, reserved 1056768K
[9.405s][info][gc,heap,exit] class space used 511K, capacity 530K, committed 640K, reserved 1048576K
total is the committed memory; the range [0x0000000700000000, 0x0000000800000000) is the reserved space.
If you want to print heap at every GC rather than at VM exit, use
-XX:+PrintHeapAtGC in JDK 8, or -Xlog:gc+heap=debug in JDK 9+.
How can I find Java heap size and memory used (Linux)? - Stack Overflow
How to print out Java jvm memory use for debugging purposes? - Stack Overflow
Windows Java command line to know the memory settings - Stack Overflow
How can I get the memory that my Java program uses via Java's Runtime API? - Stack Overflow
Each Java process has a pid, which you first need to find with the jps command.
Once you have the pid, you can use jstat -gc [insert-pid-here] to find statistics of the behavior of the garbage collected heap.
jstat -gccapacity [insert-pid-here]will present information about memory pool generation and space capabilities.jstat -gcutil [insert-pid-here]will present the utilization of each generation as a percentage of its capacity. Useful to get an at a glance view of usage.
See jstat docs on Oracle's site.
This command shows the configured heap sizes in bytes.
java -XX:+PrintFlagsFinal -version | grep HeapSize
It works on Amazon AMI on EC2 as well.
Here's a snippet from a piece of code we have that periodically logs the memory usage of our app:
import java.lang.management.GarbageCollectorMXBean
import java.lang.management.ManagementFactory
import java.lang.management.MemoryPoolMXBean
import java.lang.management.MemoryUsage
log("Heap", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage());
log("NonHeap", ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage());
List<MemoryPoolMXBean> beans = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean bean: beans) {
log(bean.getName(), bean.getUsage());
}
for (GarbageCollectorMXBean bean: ManagementFactory.getGarbageCollectorMXBeans()) {
log(bean.getName(), bean.getCollectionCount(), bean.getCollectionTime());
}
You can try visualVM, a Java profiler that goes with every JDK. You will find it in the "bin" folder.
If you're using Sun's JVM, -XX:+PrintFlagsFinal will print out all JVM settings:
java -XX:+PrintFlagsFinal ...
The maximum heap size is shown as MaxHeapSize:
uintx MaxHeapSize := 1073741824 {product}
The value is in bytes, so in the above example it's 1GB.
You can use jinfo (which is part of the JDK) to show the environment with which the JVM was started. If any non-standard settings were specified, it will also show them:
Attaching to process ID 2520, please wait... Debugger attached successfully. Client compiler detected. JVM version is 23.3-b01 Java System Properties: java.runtime.name = Java(TM) SE Runtime Environment java.vm.version = 23.3-b01 ... java.vm.specification.name = Java Virtual Machine Specification java.runtime.version = 1.7.0_07-b10 java.awt.graphicsenv = sun.awt.Win32GraphicsEnvironment os.arch = x86 java.vm.specification.vendor = Oracle Corporation ... java.specification.name = Java Platform API Specification java.class.version = 51.0 sun.management.compiler = HotSpot Client Compiler user.timezone = Europe/Berlin java.awt.printerjob = sun.awt.windows.WPrinterJob java.vm.info = mixed mode, sharing java.version = 1.7.0_07 ... VM Flags: -Xmx512m
You're doing it correctly. The way to get memory usage is exactly as you described:
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()
But the reason your program always returns the same memory usage is because you are not creating enough objects to overcome the precision limitations of the freeMemory method. Although it has byte resolution, there is no guarantee for how precise freeMemory needs to be. The javadoc says as much:
an approximation to the total amount of memory currently available for future allocated objects, measured in bytes.
Try the following, which creates two million NewObject instances, and prints out each time the result of freeMemory changes:
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
long prevTotal = 0;
long prevFree = rt.freeMemory();
for (int i = 0; i < 2_000_000; i++) {
long total = rt.totalMemory();
long free = rt.freeMemory();
if (total != prevTotal || free != prevFree) {
System.out.println(
String.format("#%s, Total: %s, Free: %s, Diff: %s",
i,
total,
free,
prevFree - free));
prevTotal = total;
prevFree = free;
}
map.put(i, new NewObject());
}
}
On my machine, I see output like the following
#0, Total: 513998848, Free: 508635256, Diff: 0
#21437, Total: 513998848, Free: 505953496, Diff: 2681760
#48905, Total: 513998848, Free: 503271728, Diff: 2681768
#73394, Total: 513998848, Free: 500589960, Diff: 2681768
#103841, Total: 513998848, Free: 497908192, Diff: 2681768
...
Notice how the reported free memory did not change until the 21,437th object was instantiated? The numbers suggest freeMemory for the JVM I'm using (Java7 Win 64-bit) has a precision of just over 2.5MB (although if you run the experiment, you'll see this number varies).
-- Edit --
This code is the same as above, but prints more details about memory usage. Hopefully it's a bit clearer how the JVM's memory usage behaves. We continuously allocate new objects in a loop. During each iteration, if the totalMemory or freeMemory is the same as the last iteration, we don't print anything. But if either has changed, we report current memory usage. The ∆ values represent the difference between current usage and the previous memory report.
public static void main(String[] args) {
Runtime rt = Runtime.getRuntime();
long prevTotal = 0;
long prevFree = rt.freeMemory();
for (int i = 0; i < 2_000_000; i++) {
long total = rt.totalMemory();
long free = rt.freeMemory();
if (total != prevTotal || free != prevFree) {
long used = total - free;
long prevUsed = (prevTotal - prevFree);
System.out.println(
"#" + i +
", Total: " + total +
", Used: " + used +
", ∆Used: " + (used - prevUsed) +
", Free: " + free +
", ∆Free: " + (free - prevFree));
prevTotal = total;
prevFree = free;
}
map.put(i, new NewObject());
}
}
On my notebook, I see the following output. Note your results will differ depending on OS, hardware, JVM implementation, etc.:
#0, Total: 83427328, Used: 1741048, ∆Used: 83427328, Free: 81686280, ∆Free: 0
#3228, Total: 83427328, Used: 1741080, ∆Used: 32, Free: 81686248, ∆Free: -32
#3229, Total: 83427328, Used: 2176280, ∆Used: 435200, Free: 81251048, ∆Free: -435200
#7777, Total: 83427328, Used: 2176312, ∆Used: 32, Free: 81251016, ∆Free: -32
#7778, Total: 83427328, Used: 2611536, ∆Used: 435224, Free: 80815792, ∆Free: -435224
...
#415056, Total: 83427328, Used: 41517072, ∆Used: 407920, Free: 41910256, ∆Free: -407920
#419680, Total: 145358848, Used: 39477560, ∆Used: -2039512, Free: 105881288, ∆Free: 63971032
#419681, Total: 145358848, Used: 40283832, ∆Used: 806272, Free: 105075016, ∆Free: -806272
...
There are a few observations from this data:
- Used memory tends to increase, as expected. Used memory includes live objects and garbage.
- But used memory decreases during a GC, because garbage has been discarded. For example, this occurred at #419680.
- The amount of free memory reduces in chunks, not byte-by-byte. The chunks vary in size. Sometimes the chunks are really tiny, like 32 bytes, but usually they are larger, like 400K, or 800K. So it appears the chunk size will vary a fair bit. But compared to total heap size, the variation appears tiny. For example, at #419681 the chunk size is only 0.6% of the total heap size.
- Free memory tends to decrease, as expected, until a GC kicks in and cleans up garbage. When this occurs, free memory increases pretty dramatically, depending on the amount of discarded garbage.
- This test generates a lot of garbage. As the hashmap grows in size, it rehashes its contents, thus generating a lot of garbage.
I've got the following methods
public static long getMaxMemory() {
return Runtime.getRuntime().maxMemory();
}
public static long getUsedMemory() {
return getMaxMemory() - getFreeMemory();
}
public static long getTotalMemory() {
return Runtime.getRuntime().totalMemory();
}
public static long getFreeMemory() {
return Runtime.getRuntime().freeMemory();
}
which return the (used) Memory in bytes.
If you want to recalculate to MiB I've got:
private static final long MEGABYTE_FACTOR = 1024L * 1024L;
private static final DecimalFormat ROUNDED_DOUBLE_DECIMALFORMAT;
private static final String MIB = "MiB";
static {
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(Locale.ENGLISH);
otherSymbols.setDecimalSeparator('.');
otherSymbols.setGroupingSeparator(',');
ROUNDED_DOUBLE_DECIMALFORMAT = new DecimalFormat("####0.00", otherSymbols);
ROUNDED_DOUBLE_DECIMALFORMAT.setGroupingUsed(false);
}
public static String getTotalMemoryInMiB() {
double totalMiB = bytesToMiB(getTotalMemory());
return String.format("%s %s", ROUNDED_DOUBLE_DECIMALFORMAT.format(totalMiB), MIB);
}
public static String getFreeMemoryInMiB() {
double freeMiB = bytesToMiB(getFreeMemory());
return String.format("%s %s", ROUNDED_DOUBLE_DECIMALFORMAT.format(freeMiB), MIB);
}
public static String getUsedMemoryInMiB() {
double usedMiB = bytesToMiB(getUsedMemory());
return String.format("%s %s", ROUNDED_DOUBLE_DECIMALFORMAT.format(usedMiB), MIB);
}
public static String getMaxMemoryInMiB() {
double maxMiB = bytesToMiB(getMaxMemory());
return String.format("%s %s", ROUNDED_DOUBLE_DECIMALFORMAT.format(maxMiB), MIB);
}
public static double getPercentageUsed() {
return ((double) getUsedMemory() / getMaxMemory()) * 100;
}
public static String getPercentageUsedFormatted() {
double usedPercentage = getPercentageUsed();
return ROUNDED_DOUBLE_DECIMALFORMAT.format(usedPercentage) + "%";
}
Show the command line column in task manager, which should have the settings assuming they were passed on the command line:

Note that the below answer might require JMX to be enabled - I believe it's disabled by default in public JRE, and requires a restart of the JVM to change it, which would be rather useless in your case. Still, worth a shot?
Whether they work or not will also depend on the specific native wrapping method used by this application.
You should be able to copy these tools along with jli.dll from a JDK with a matching minor version and architecture to the JRE you're running. You could also run the tools remotely, though that's less likely to work without some initial set up due to the security requirements for remote connections.
The jps tool, available in the JDK, should be able to provide this information with the command jps -v. If you have multiple Java processes running, you can identify them by the PID in the first column.
Example output on Netbeans (PID 9056) (which uses a native wrapper similar to your application):
9056 -Dnetbeans.importclass=org.netbeans.upgrade.AutoUpgrade -Dnetbeans.accept_
license_class=org.netbeans.license.AcceptLicense -client -Xss2m -Xms32m -XX:Perm
Size=32m -Dapple.laf.useScreenMenuBar=true -Dapple.awt.graphics.UseQuartz=true -
Dsun.java2d.noddraw=true -Dsun.java2d.dpiaware=true -Dsun.zip.disableMemoryMappi
ng=true -Xmx1024m <snip>
Notice the -Xss, -Xms and -Xmx arguments.
Another thing you can try is jinfo, which allows you to target a specific PID, e.g. jinfo 9056.
NOTE - This utility is unsupported and may or may not be available in future versions of the JDK.
You could also try jconsole and jvisualvm, though they seem to have trouble attaching to wrapped JVMs and listing VM arguments, from my testing.
That is the output from jmap -histo. Possibly jmap -histo:live. You run it as an external tool and supply the pid of the JVM. It is provided in the bin directory of your jdk installation.
It is typically safe to run in production but you should be aware of that jmap -histo:live triggers a full GC, which is necessary to only show the live objects. jmap -histo does not trigger a GC.
jmap documentation
Alternatively you can create a heap-dump. And then use the jmap utility to obtain a histogram from the heap dump. If you are using IBM's JDK you can use IBM's Memory Analyzer tool (MAT) to get the histogram
https://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/memleaks.html#gbywm http://www.ibm.com/developerworks/java/jdk/tools/memoryanalyzer/