<div dir="ltr"><p style="color:rgb(0,0,0);font-size:12.8px">Hi, </p><p style="color:rgb(0,0,0);font-size:12.8px">I am running a test which is trying to log memory info. when free-heap-percentage is under a certain threshold. But noticed that when heap is around `-XX:CMSInitiatingOccupancyFraction`, Runtime.getRuntime().freeMemory() can report wrong values when compared to memory info from GC logs. It reports as if whole heap is nearly occupied, but actually there exists lots of free-memory. Issue is observable for a short-time period. Later it starts to report expected values. (Also tried my test with G1 defaults and Runtime.getRuntime().freeMemory() reported as expected)</p><p style="color:rgb(0,0,0);font-size:12.8px">Issue is easily visible on large heaps.</p><p style="color:rgb(0,0,0);font-size:12.8px">Is my assumption correct? Can Runtime.getRuntime().freeMemory() report wrong free-memory info for a while? Or how can we explain this situation?</p><p style="color:rgb(0,0,0);font-size:12.8px">Here is my test and how i run it from command line:</p><pre style="white-space:pre-wrap;color:rgb(0,0,0);word-wrap:break-word"><font color="#000000">[PROBLEMATIC RUN WITH CMS]--> java -verbose:gc -Xms60G -Xmx60G -XX:CMSInitiatingOccupancyFraction=2 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -cp target/free-memory-issue-1.0-SNAPSHOT.jar FreeMemory<br></font></pre><pre style="white-space:pre-wrap;color:rgb(0,0,0);word-wrap:break-word"><pre style="white-space:pre-wrap;word-wrap:break-word">[OK RUN WITH G1]--> java -verbose:gc -Xms60G -Xmx60G -XX:+UseG1GC -cp target/free-memory-issue-1.0-SNAPSHOT.jar FreeMemory</pre></pre><pre style="white-space:pre-wrap;color:rgb(0,0,0);word-wrap:break-word">public class FreeMemory {
static final int MB = 1024 * 1024;
static final String MESSAGE = "runtime.maxMemory=%d%s, runtime.totalMemory=%d%s, runtime.freeMemory=%d%s," +
" runtime.usedMemory=%d%s, runTime.availableMemory=%d%s, freeHeapPercentage=%.2f";
public static void main(String[] args) throws InterruptedException {
final ConcurrentHashMap map = new ConcurrentHashMap();
Runtime runtime = Runtime.getRuntime();
int availableProcessors = runtime.availableProcessors();
int threadCount = availableProcessors * 4;
ArrayList<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < threadCount; i++) {
threads.add(new Thread(new Runnable() {
@Override
public void run() {
Random random = new Random();
while (true) {
byte[] value = new byte[1024];
random.nextBytes(value);
map.put(random.nextInt(), value);
if (hasReachedMinFreeHeapPercentage(12)) {
break;
}
}
}
}));
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
out.print("\n\n\nEnd of run...now we expect to see actual used-memory value\n");
while (true) {
printCurrentMemoryInfo();
parkNanos(SECONDS.toNanos(5));
}
}
static boolean hasReachedMinFreeHeapPercentage(int minFreeHeapPercentage) {
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long availableMemory = freeMemory + (maxMemory - totalMemory);
double freeHeapPercentage = 100D * availableMemory / maxMemory;
if (freeHeapPercentage < minFreeHeapPercentage) {
String unit = "M";
out.println(format(MESSAGE, toMB(maxMemory), unit, toMB(totalMemory), unit, toMB(freeMemory), unit,
toMB(totalMemory - freeMemory), unit, toMB(availableMemory), unit, freeHeapPercentage));
return true;
}
return false;
}
static void printCurrentMemoryInfo() {
Runtime runtime = Runtime.getRuntime();
long maxMemory = runtime.maxMemory();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long availableMemory = freeMemory + (maxMemory - totalMemory);
double freeHeapPercentage = 100D * availableMemory / maxMemory;
String unit = "M";
out.println(format(MESSAGE, toMB(maxMemory), unit, toMB(totalMemory), unit, toMB(freeMemory), unit,
toMB(totalMemory - freeMemory), unit, toMB(availableMemory), unit, freeHeapPercentage));
}
static int toMB(long bytes) {
return (int) Math.rint(bytes / MB);
}
}<br></pre><p style="color:rgb(0,0,0);font-size:12.8px">Java version:</p><p style="color:rgb(0,0,0);font-size:12.8px">openjdk version "1.8.0_91"<br></p><p style="color:rgb(0,0,0);font-size:12.8px">OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-0ubuntu4~14.04-b14)</p><p style="color:rgb(0,0,0);font-size:12.8px">OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)</p><div style="color:rgb(0,0,0);font-size:12.8px"><br></div><div style="color:rgb(0,0,0);font-size:12.8px">OS info:</div><p style="color:rgb(0,0,0);font-size:12.8px">Linux version 3.13.0-74-generic (buildd@lcy01-07) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #118-Ubuntu SMP Thu Dec 17 22:52:10 UTC 2015</p><p style="color:rgb(0,0,0);font-size:12.8px">Distributor ID: Ubuntu</p><p style="color:rgb(0,0,0);font-size:12.8px">Description: Ubuntu 14.04.3 LTS</p><p style="color:rgb(0,0,0);font-size:12.8px">Release: 14.04</p><p style="color:rgb(0,0,0);font-size:12.8px"><br></p><p style="color:rgb(0,0,0);font-size:12.8px">Thanks in advance,</p><div><br></div><br>
</div>