我们都知道在启动Java时,可以通过Xms和Xmx这两个参数来指定Java的最小堆内存和最大堆内存,但这两个参数的最小值又可以是多少呢?
下面我们通过OpenJDK源码看下。不过在此之前,我们先明确下OpenJDK的版本:
➜ jdk hg id 76072a077ee1 jdk-11+28
好了,进入源码部分。
首先,通过Xms和Xmx找到对应的参数解析代码(src/hotspot/share/runtime/arguments.cpp)
} else if (match_option(option, "-Xms", &tail)) {
julong long_initial_heap_size = 0;
// an initial heap size of 0 means automatically determine
ArgsRange errcode = parse_memory_size(tail, &long_initial_heap_size, 0);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid initial heap size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
set_min_heap_size((size_t)long_initial_heap_size);
// Currently the minimum size and the initial heap sizes are the same.
// Can be overridden with -XX:InitialHeapSize.
if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// -Xmx
} else if (match_option(option, "-Xmx", &tail) || match_option(option, "-XX:MaxHeapSize=", &tail)) {
julong long_max_heap_size = 0;
ArgsRange errcode = parse_memory_size(tail, &long_max_heap_size, 1);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid maximum heap size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
// Xmaxf
}
其中,第11行调用了set_min_heap_size方法,传入的是Xms的值 ,对应的代码为(src/hotspot/share/runtime/arguments.hpp)
// -Xms
static size_t min_heap_size() { return _min_heap_size; }
static void set_min_heap_size(size_t v) { _min_heap_size = v; }
由上我们也可以看到,调用min_heap_size()方法返回的也是这个值。
第14行设置InitialHeapSize为Xms的值。
第27行设置MaxHeapSize为Xmx的值。
然后,我们再通过InitialHeapSize、MaxHeapSize找到代码(src/hotspot/share/gc/shared/collectorPolicy.cpp)
void CollectorPolicy::initialize_flags() {
assert(_space_alignment != 0, "Space alignment not set up properly");
assert(_heap_alignment != 0, "Heap alignment not set up properly");
assert(_heap_alignment >= _space_alignment,
"heap_alignment: " SIZE_FORMAT " less than space_alignment: " SIZE_FORMAT,
_heap_alignment, _space_alignment);
assert(_heap_alignment % _space_alignment == 0,
"heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT,
_heap_alignment, _space_alignment);
if (FLAG_IS_CMDLINE(MaxHeapSize)) {
if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) {
vm_exit_during_initialization("Initial heap size set to a larger value than the maximum heap size");
}
if (_min_heap_byte_size != 0 && MaxHeapSize < _min_heap_byte_size) {
vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified");
}
}
// Check heap parameter properties
if (MaxHeapSize < 2 * M) {
vm_exit_during_initialization("Too small maximum heap");
}
if (InitialHeapSize < M) {
vm_exit_during_initialization("Too small initial heap");
}
if (_min_heap_byte_size < M) {
vm_exit_during_initialization("Too small minimum heap");
}
在上面的代码中我们发现,MaxHeapSize不能小于2M,InitialHeapSize不能小于1M。
上面还有个验证是_min_heap_byte_size不能小于1M,而_min_heap_byte_size值是来自(src/hotspot/share/gc/shared/collectorPolicy.cpp)
CollectorPolicy::CollectorPolicy() :
_space_alignment(0),
_heap_alignment(0),
_initial_heap_byte_size(InitialHeapSize),
_max_heap_byte_size(MaxHeapSize),
_min_heap_byte_size(Arguments::min_heap_size())
{}
Arguments::min_heap_size()方法,而这个方法也正是我们上面提到过的方法,返回的就是Xms的值。
综上可知,Xms最小要是1M,Xmx最小要是2M。
后来在 Java command 文档也发现有类似的说明,看来官方文档还是要好好看下的。
-Xms size
This value must be a multiple of 1024 and greater than 1 MB.
-Xmx size
This value must be a multiple of 1024 and greater than 2 MB.