We have several bugs right now (as of 3.1.2) which are seemingly associated
with the heap size test that the Module Manager does. One thing which would
be helpful in sorting out these problems is to prohibit max heap sizes which
are larger than the amount of physical RAM in the machine. In order to do
this, we have to determine how much physical RAM there is, which is not
straightforward because Java provides no API for getting this information.
Hence, we have to haul out something different for each platform to get the
amount of RAM.
Here’s what I have so far:
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
public class RAMTest {
public static void main(String[] args) throws Exception {
final String os = System.getProperty("os.name").toLowerCase();
long ram_mbytes = 0L;
if (os.startsWith("windows")) {
final Process p = new ProcessBuilder("systeminfo").start();
InputStream in = p.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = r.readLine()) != null) {
if (line.startsWith("Total Physical Memory:")) {
ram_mbytes = Long.parseLong(
line.substring(22, line.lastIndexOf(' ')).trim());
break;
}
}
}
else if (os.startsWith("linux")) {
ram_mbytes = new File("/proc/kcore").length() >> 20;
}
else if (os.startsWith("mac os x")) {
final Process p = new ProcessBuilder("sysctl", "hw.memsize").start();
InputStream in = p.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(in));
String line = r.readLine();
ram_mbytes = Long.parseLong(line.substring(line.indexOf(' '))) >> 20;
}
else {
ram_mbytes = 0L;
}
System.out.println(ram_mbytes + " MB");
}
}
Explanation:
Linux: This one is the simplest. /proc/kcore is the file which corresponds
to the physical RAM. We use java.io.File to stat it. I think this will work
no matter what Linux distro you have.
Windows: We call the system command ‘systeminfo’. This is ugly because
we have to parse text, and slow because there’s a gigantic amount of stuff
which systeminfo checks on. I’ve tested that this works on XP, but I have
no clue if the command even exists on other versions of Windows. Surely
there’s a better way, but I don’t know it.
Mac OS X: We call “sysctl hw.memsize”, which gives us the amount of RAM.
I haven’t tested this one myself.
I’m attaching a ZIP archive containing the compiled class. Please give
this a try on your machine and let me know (1) if it works at all, and (2)
if it’s remotely accurate. (To run: java RAMTest)
I decided to take another tack for finding physical RAM on Windows. The
systeminfo command is too slow due to the amount of crap it has to poll
and anyway I’m unsure that it even exists on all versions of Windows we
support.
What I’ve done instead is try out JNA, which uses some scary reflection
under the hood to let you make calls to arbitrary C/C++ functions in
arbitrary libraries. In this case, the function we want is
GetGlobalMemoryStatusEx() from Kernel32.dll. It turns out to be dead easy
to do this and much faster than running systeminfo.
To try this out on Windows:
java -cp jna.jar;. RAMTest
Also, I’d like to hear back from someone using a Mac as to whether this
successfully detects how much RAM you have. An updated version of the
archive is here:
Rather than running the sysctl command and parsing the output, I’m now
calling sysctlbyname(3) from the C library. The code is a bit cleaner
this way, if works.