Short answer: All memory sizes used by the JVM command line arguments are specified in the traditional binary units, where a kilobyte is 1024 bytes, and the others are increasing powers of 1024.
Long answer:
This documentation page on the command line arguments says the following applies to all the arguments accepting memory sizes:
For example, to set the size to 8 GB, you can specify either
8g,8192m,8388608k, or8589934592as the argument.
For -Xmx, it gives these specific examples:
The following examples show how to set the maximum allowed size of allocated memory to 80 MB using various units:
-Xmx83886080
-Xmx81920k
-Xmx80m
Before I thought to check the documentation (I assumed you already had?), I checked the source of HotSpot and found the memory values are parsed in src/share/vm/runtime/arguments.cpp by the function atomull (which seems to stand for "ASCII to memory, unsigned long long"):
// Parses a memory size specification string.
static bool atomull(const char *s, julong* result) {
julong n = 0;
int args_read = sscanf(s, JULONG_FORMAT, &n);
if (args_read != 1) {
return false;
}
while (*s != '\0' && isdigit(*s)) {
s++;
}
// 4705540: illegal if more characters are found after the first non-digit
if (strlen(s) > 1) {
return false;
}
switch (*s) {
case 'T': case 't':
*result = n * G * K;
// Check for overflow.
if (*result/((julong)G * K) != n) return false;
return true;
case 'G': case 'g':
*result = n * G;
if (*result/G != n) return false;
return true;
case 'M': case 'm':
*result = n * M;
if (*result/M != n) return false;
return true;
case 'K': case 'k':
*result = n * K;
if (*result/K != n) return false;
return true;
case '\0':
*result = n;
return true;
default:
return false;
}
}
Those constants K, M, G are defined in src/share/vm/utilities/globalDefinitions.hpp:
const size_t K = 1024;
const size_t M = K*K;
const size_t G = M*K;
All this confirms the documentation, except that support for the T suffix for terabytes was apparently added later and is not documented at all.
It is not mandatory to use a unit multiplier, so if you want one billion bytes you can write -Xmx1000000000. If you do use a multiplier, they're binary, so -Xmx1G means 230 bytes, or one stick o' RAM.
(Which is not really surprising, because Java predates the IEC's attempt to retroactively redefine existing words. Confusion could have been saved if the IEC had merely advised disambiguating the memory units with the qualifiers "binary" and "decimal" the occasional times their meaning wasn't clear. E.g., binary gigabytes (GB2) = 10243 bytes, and decimal gigabytes (GB10) = 10003 bytes. But no, they redefined the words everyone was already using, inevitably exploding confusion, and leaving us stuck with these clown terms "gibibyte", "tebibyte" and the rest. Oh God spare us.)
Answer from Boann on Stack OverflowShort answer: All memory sizes used by the JVM command line arguments are specified in the traditional binary units, where a kilobyte is 1024 bytes, and the others are increasing powers of 1024.
Long answer:
This documentation page on the command line arguments says the following applies to all the arguments accepting memory sizes:
For example, to set the size to 8 GB, you can specify either
8g,8192m,8388608k, or8589934592as the argument.
For -Xmx, it gives these specific examples:
The following examples show how to set the maximum allowed size of allocated memory to 80 MB using various units:
-Xmx83886080
-Xmx81920k
-Xmx80m
Before I thought to check the documentation (I assumed you already had?), I checked the source of HotSpot and found the memory values are parsed in src/share/vm/runtime/arguments.cpp by the function atomull (which seems to stand for "ASCII to memory, unsigned long long"):
// Parses a memory size specification string.
static bool atomull(const char *s, julong* result) {
julong n = 0;
int args_read = sscanf(s, JULONG_FORMAT, &n);
if (args_read != 1) {
return false;
}
while (*s != '\0' && isdigit(*s)) {
s++;
}
// 4705540: illegal if more characters are found after the first non-digit
if (strlen(s) > 1) {
return false;
}
switch (*s) {
case 'T': case 't':
*result = n * G * K;
// Check for overflow.
if (*result/((julong)G * K) != n) return false;
return true;
case 'G': case 'g':
*result = n * G;
if (*result/G != n) return false;
return true;
case 'M': case 'm':
*result = n * M;
if (*result/M != n) return false;
return true;
case 'K': case 'k':
*result = n * K;
if (*result/K != n) return false;
return true;
case '\0':
*result = n;
return true;
default:
return false;
}
}
Those constants K, M, G are defined in src/share/vm/utilities/globalDefinitions.hpp:
const size_t K = 1024;
const size_t M = K*K;
const size_t G = M*K;
All this confirms the documentation, except that support for the T suffix for terabytes was apparently added later and is not documented at all.
It is not mandatory to use a unit multiplier, so if you want one billion bytes you can write -Xmx1000000000. If you do use a multiplier, they're binary, so -Xmx1G means 230 bytes, or one stick o' RAM.
(Which is not really surprising, because Java predates the IEC's attempt to retroactively redefine existing words. Confusion could have been saved if the IEC had merely advised disambiguating the memory units with the qualifiers "binary" and "decimal" the occasional times their meaning wasn't clear. E.g., binary gigabytes (GB2) = 10243 bytes, and decimal gigabytes (GB10) = 10003 bytes. But no, they redefined the words everyone was already using, inevitably exploding confusion, and leaving us stuck with these clown terms "gibibyte", "tebibyte" and the rest. Oh God spare us.)
You have two options to get answer for your question:
a) inspect source code of JDK. Sorry I was unable to google it in 5 minutes.
b) write a simulation, run it several times and make some observations.
public class A {
public static void main(String[] args) throws Exception {
System.out.println("total: " + Runtime.getRuntime().totalMemory());
}
}
And run it several times:
java -Xms130m -Xmx2G A
total: 131072000
java -Xms131m -Xmx2G A
total: 132644864
java -Xms132m -Xmx2G A
total: 132644864
java -Xms133m -Xmx2G A
total: 134742016
java -Xms134m -Xmx2G A
total: 134742016
So educated guess is that java uses not an exact number, but 2^n approximation of the number you requested.
Videos
Edit: Solved, just set them both to the same value!
---
So when running my server (which has 8GB or RAM) I set my Xms to 2G (minimum RAM) and Xmx to 6GB (maximum RAM). From what I understand this means the server will always use 2GB of RAM but can take up to 6GB if it needs it. It's running on a dedicated Ubuntu server that does nothing but run the MC server, so 2GB for the OS etc. should be fine.
However, I've also read that giving MC too much RAM is bad, and garbage collection will go haywire. I managed to find some good but very cheap RAM so I'll be upgrading to 16GB of RAM this weekend.
My question is, how to determine what to set the min RAM to and what the max RAM? I just picked 2GB as the minimum value at random, as it seemed like a good amount to give the server at minimum. When I put the 16GB in I want to allocate 12GB to my MC server, should I keep the min at 2GB and set the max to 12GB? Could this lead to issues?
My launch parameters (added some line breaks for readability):
java -server -Xms2G -Xmx6G -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=100 -XX:+DisableExplicitGC -XX:TargetSurvivorRatio=90 -XX:G1NewSizePercent=50 -XX:G1MaxNewSizePercent=80 -XX:G1MixedGCLiveThresholdPercent=35 -XX:+AlwaysPreTouch -XX:+ParallelRefProcEnabled -Dusing.aikars.flags=mcflags.emc.gs -jar $(ls -v | grep -i "FTBServer.*jar\|forge.*jar\|paper-*.*jar\|spigot-*.*jar\|minecraft_server.*jar" | head -n 1) nogui
While I haven't run any JRuby apps on Tomcat, I have run ColdFusion apps on varied J2EE app servers, and I also have had similar issues.
In these FAQs, you'll see that SOracle says that on 32-bit Windows, you'll be limited to a max heap size of 1.4 to 1.6 GB. I never was able to get it stable that high, and I suspect you're running a similar configuration.
My guess is that your requests are taking a long time to run b/c with a heap size that high, the JVM has allocated more physical memory than Windows had to give, and thus Windows spends a lot of time swapping pages in and out of memory to disk so it can provide the required amount of memory to the JVM.
My recommendation, although counter-intuitive, would be that you actually lower the max heap size to somewhere around 1.2 GB. You can raise the min size as well, if you notice that there are slow-downs in the app's request processing while the JVM has to ask Windows for more memory to increase the size of its heap as it fills with uncollected objects.
Part of your problem is that you are probably starving all other processes for ram. My general rule of thumb for -Xms and -Xmx are as follows:
-Xms : <System_Memory>*.5
-Xmx : <System_Memeory>*.75
So on a 4GB systems it would be: -Xms2048m -Xmx3072m, and in your case I would go with -Xms896m -Xmx1344
-Xmx15G will set the maximum heap size to 15 gig. Java will only allocate what it needs as it runs. If you don't set it, it will only use the default. For info on the default, see this post.
-Xms15G sets the minimum heap to 15 gig. This forces java to allocate 15 gig of heap space before it starts executing, whether it needs it or not.
Usually you can set them both to appropriate values depending on how you're tuning the JVM.
In Java 6, the default maximum heap size is determined by the amount of system memory present.
According to the Garbage Collector Ergonomics page, the maximum heap size is:
Smaller of 1/4th of the physical memory or 1GB. Before J2SE 5.0, the default maximum heap size was 64MB.
By using the -Xmx switch can be used to change the maximum heap size. See the java - the Java application launcher documentation for usage details.