get real RAM usage of current JVM with Java
Asked Answered
C

2

5

In HTOP you can see the RES value (resident size) which shows how much of your RAM your JVM process is really taking.

Now I want to get that value by only using pure Java. If you tell me it's just not possible, that's fine as well.

Let me explain all the attempts I made with an application that shows a RES value of 887M in htop:

  1. Combining committed HeapMemory and non Heapmemory via MemoryMXBean gives me 726M
  2. Adding up all commited memory of all ManagementFactory.getMemoryPoolMXBeans() gives me 737M
  3. runtime.totalMemory() gives 515M

Any ideas what else I could try?

Cooe answered 31/10, 2014 at 14:24 Comment(8)
There is no pure Java function which will give you this. You can estimate what it will be with some assumptions, however you are missing memory mapped files, thread stacks, shared libraries and direct memory which is not included in the accounting you mention. In the sort of programs I write, memory mapped files can exceed everything else if you are using them right.Cincinnatus
So I am essentially forced to use an external tool like top or use JNI magic?Cooe
Correct, though in general you would have an external program monitor your usage, what action do you want to take within the application based on this number? Note: having a low number can be a bad thing and a high number can be a good thing.Cincinnatus
What are you trying to do with this? For a Java-based monitoring tool, it would be pretty useful, but having your application react based on overall system memory isn't. Even if the system has 256GB and is 90% free, your JVM may be restricted to 128MB, so it doesn't do you any good.Insulting
I am tasked with creating a logging application for our tomcat that records CPU usage, per thread CPU usage and various memory metrics. (Essentially a little self made profiler) Everything is working fine, besides the RAM usage monitoring. Sadly, where I work JNI is frowned upon and if your alternative is reading the output of an external application you naturally want a "native" way.Cooe
Did you make the comparison between methods in the same run with consecutive calls or in different runs? Are you sure the GC did not bump while asking this info?Mattland
I collect the data every few seconds AND forced GC.Cooe
Is there a reason your management doesn't want to use jconsole?Fledge
S
3

Assuming you are running Linux, just read /proc/self/status file and look for VmRSS: line.

Or parse /proc/self/smaps to get comprehensive memory information for the current process.

Spermaceti answered 31/10, 2014 at 18:22 Comment(2)
I don't believe that this is pure java (it depends on system functions and breaks under windows), although this is a useful answer.Bradfield
This is probably the cleanest, most standard way. To fill in Windows support, you might look into using the WMI COM interfaces (discussed here).Insulting
V
3

I've written:

public class RuntimeUtil {
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);
}

private RuntimeUtil() {
    //No Init
}

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();
}

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) + "%";
}

private static double bytesToMiB(long bytes) {
    return ((double) bytes / MEGABYTE_FACTOR);
}

public static String getHostAdress() {
    try {
        java.net.InetAddress addr = java.net.InetAddress.getLocalHost();
        return addr.getHostAddress();
    } catch (UnknownHostException e) {
        // looks like a strange machine
        System.out.println(e.getMessage());
    }
    return StringUtil.EMPTY;
}

public static String getHostName() {
    try {
        java.net.InetAddress addr = java.net.InetAddress.getLocalHost();
        return addr.getHostName();
    } catch (UnknownHostException e) {
        // looks like a strange machine
        System.out.println(e.getMessage());
    }
    return StringUtil.EMPTY;
}

public static String getSystemInformation() {
    return String.format("SystemInfo=Current heap:%s; Used:%s; Free:%s; Maximum Heap:%s; Percentage Used:%s",
            getTotalMemoryInMiB(),
            getUsedMemoryInMiB(),
            getFreeMemoryInMiB(),
            getMaxMemoryInMiB(),
            getPercentageUsedFormatted());
}
Virgule answered 21/3, 2018 at 14:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.