find how much physical RAM your machine has

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:

  1. 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.

  2. 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.

  3. 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)

My result

Exception in thread “main” java.lang.NumberFormatException: For input
string: 3,071"

At java.lang.NumberFormatException.forInputString(unk source)
At java.lang.Long.parseLong
At java.lang.Long.parseLong
At RAMTest.main(RAMTest.java:21)

Post generated using Mail2Forum (mail2forum.com)

Thus spake “Tim McCarron”:

Thank you, Windows, for putting commas in your numbers. ARGH.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Cute. I would have done something horrible with /proc/meminfo.

  • M.

Post generated using Mail2Forum (mail2forum.com)

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:

nomic.net/~uckelman/tmp/vassal/ramtest.zip

On Vista 32

Test 1 failed because I do not have a 1.6 JRE in my path.

Test 2:

F:\Downloads\ramtest\ramtest>“C:\Program Files\Java\jre6\bin\java” -cp jna.jar;. RAMTest
3581 MB

Which is correct.

B.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

On Mar 24, 2009, at 2:32 PM, uckelman wrote:

On a Mac, OS 10.5.6 (Leopard), Intel hardware.

4096 MB

I do note that the files as compiled required Java 1.6 to run.
After recompiling your cource with the Java 1.5 compiler it also worked.

For what it’s worth, this is what I get from running it under
Parallels on Windows XP/Pro:

$ java -cp “jna.jar;.” RAMTest
1023 MB

(The VM is given less memory…)


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Failed on Windows XP 64

image attached

never mind. Helps to type the right command! :unamused: works fine

Thus spake Thomas Russ:

Thanks for having a look. I’ve uploaded a slightly different test for the
Mac, here:

nomic.net/~uckelman/tmp/vassal/ramtest-2.zip

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.

Also, this one is built to work with Java 1.5.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

On Mar 25, 2009, at 7:00 AM, Joel Uckelman wrote:

Fails miserably:

tar% java -cp jna.jar:. RAMTest
Error 34: Result too large
-1 MB

Perhaps a larger buffer is needed?


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Thus spake Thomas Russ:

I would say it fails admirably, since this demonstrates that the bindings
for strerror() work. :slight_smile:

I think sysctl will be giving us a long, not an int. Try changing line 119
from this:

final IntByReference oldp = new IntByReference(0);

to this:

final LongByReference oldp = new LongByReference(0);

and adding the import for LongByReference:

import com.sun.jna.ptr.LongByReference;


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

On Mar 25, 2009, at 9:43 AM, Joel Uckelman wrote:

Yes, I was pleased to see the nice error string.

Same result:

tar% java -cp jna.jar:. RAMTest
Error 34: Result too large
-1 MB

tar% grep LongBy RAMTest.java
import com.sun.jna.ptr.LongByReference;
final LongByReference oldp = new LongByReference(0);

Ah, but I had a thought.
I needed to change the line after your line 119 from int.class to
long.class:

final IntByReference oldlenp =
new IntByReference(Native.getNativeSize(long.class));

And then it works:

tar% java -cp jna.jar:. RAMTest
4096 MB


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Thus spake Thomas Russ:

Wonderful. Thanks for trying this for me.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)