Reputation: 5778
There are similar questions out there, but they seem to avoid answering this specific question. How can I get the memory that my Java program uses via Java's Runtime API?
The answer here indicates that I can do something like this:
System.out.println("KB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024);
But this always returns the same number, no matter which program I run. For example, below I have a program where no matter how many numbers I put in the map, the memory usage stays the same.
package memoryTest;
import java.util.HashMap;
import java.util.Map;
public class MemoryTest {
static Map<Integer, NewObject> map = new HashMap<Integer, NewObject>();
public static void main(String[] args){
System.out.println("KB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024);
fillMemory(25);
System.out.println("KB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024);
}
static int j=0;
public static void fillMemory(int i){
for(int k=0; k< 2000; k++)
map.put(j++, new NewObject());
}
public static class NewObject{
long i = 0L;
long j = 0L;
long k = 0L;
}
}
via cambecc's main method, output is:
# 3085, Total: 128516096, Free: 127173744, Diff: 671120
# 173579, Total: 128516096, Free: 110033976, Diff: 671128
# 335207, Total: 128516096, Free: 92417792, Diff: 637544
# 672788, Total: 224198656, Free: 159302960, Diff: 1221520
# 1171480, Total: 224198656, Free: 106939136, Diff: 1221544
# 1489771, Total: 368377856, Free: 227374816, Diff: 1212984
# 1998743, Total: 368377856, Free: 182494408, Diff: 1212984
Upvotes: 72
Views: 149803
Reputation: 13715
public class MemoryUtil {
public static void print() {
Runtime runtime = Runtime.getRuntime();
long allocated = runtime.totalMemory();
long used = allocated - runtime.freeMemory();
long max = runtime.maxMemory();
long available = max - used;
log.info(String.format("Max: %d Allocated: %d Used: %d Available: %d",
toMb(max),
toMb(allocated),
toMb(used),
toMb(available)));
}
private static long toMb(long bytes) {
return bytes / 1_000_000;
}
}
Allocated
can go up to Max
.
If Available
gets close to 0, application will become unresponsive or may throw an OutOfMemoryError.
Upvotes: 0
Reputation: 1
Fair free memory:
maxMemory() - totalMemory() + freeMemory()
and it will be the same as:
maxMemory() - (used memory), where (used memory) = totalMemory() - freeMemory()
because the freeMemory()
gives you only the free available memory inside the totalMemory()
, but the totalMemory()
still can grow up to the maxMemory()
.
Upvotes: 0
Reputation: 29
public static void memoryStats() {
int mb = 1024 * 1024;
// get Runtime instance
Runtime instance = Runtime.getRuntime();
System.out.println("***** Heap utilization statistics [MB] *****\n");
// available memory
System.out.println("Total Memory: " + instance.totalMemory() / mb);
// free memory
System.out.println("Free Memory: " + instance.freeMemory() / mb);
// used memory
System.out.println("Used Memory: "
+ (instance.totalMemory() - instance.freeMemory()) / mb);
// Maximum available memory
System.out.println("Max Memory: " + instance.maxMemory() / mb);
}
REF: Here
Upvotes: 2
Reputation: 1703
Following can be used in your java method to get the memory related statistics.
// Get the Java runtime
Runtime runtime = Runtime.getRuntime();
// Run the garbage collector
runtime.gc();
// Calculate the used memory
long memory = runtime.totalMemory() - runtime.freeMemory();
System.out.println("Used memory is bytes: " + memory);
System.out.println("Used memory is megabytes: "
+ bytesToMegabytes(memory));
Upvotes: 0
Reputation: 2245
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) + "%";
}
Upvotes: 4
Reputation: 4184
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).
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:
Upvotes: 116