内存识别
在没有设置内存参数的时候,如何没有设置xms,xmx
void Arguments::set_heap_size() {
julong phys_mem;
// If the user specified one of these options, they
// want specific memory sizing so do not limit memory
// based on compressed oops addressability.
// Also, memory limits will be calculated based on
// available os physical memory, not our MaxRAM limit,
// unless MaxRAM is also specified.
bool override_coop_limit = (!FLAG_IS_DEFAULT(MaxRAMPercentage) ||
!FLAG_IS_DEFAULT(MaxRAMFraction) ||
!FLAG_IS_DEFAULT(MinRAMPercentage) ||
!FLAG_IS_DEFAULT(MinRAMFraction) ||
!FLAG_IS_DEFAULT(InitialRAMPercentage) ||
!FLAG_IS_DEFAULT(InitialRAMFraction) ||
!FLAG_IS_DEFAULT(MaxRAM));
if (override_coop_limit) {
if (FLAG_IS_DEFAULT(MaxRAM)) {
phys_mem = os::physical_memory();
FLAG_SET_ERGO(MaxRAM, (uint64_t)phys_mem);
} else {
phys_mem = (julong)MaxRAM;
}
} else {
phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM)
: (julong)MaxRAM;
}
if (FLAG_IS_DEFAULT(MaxHeapSize)) {
julong reasonable_max = (julong)((phys_mem * MaxRAMPercentage) / 100);
const julong reasonable_min = (julong)((phys_mem * MinRAMPercentage) / 100);
}
if (FLAG_IS_DEFAULT(MaxRAMPercentage) &&
!FLAG_IS_DEFAULT(MaxRAMFraction))
MaxRAMPercentage = 100.0 / MaxRAMFraction;
product(uintx, MaxRAMFraction, 4, \
"Maximum fraction (1/n) of real memory used for maximum heap " \
"size. " \
"Deprecated, use MaxRAMPercentage instead") \
range(1, max_uintx)
MaxRAMPercentage在没有设置的情况下是根据MaxRAMFraction计算的,默认MaxRAMFraction是4。这也是xmx默认是内存的四分之一。
if (FLAG_IS_DEFAULT(MinRAMPercentage) &&
!FLAG_IS_DEFAULT(MinRAMFraction))
MinRAMPercentage = 100.0 / MinRAMFraction;
product(uintx, MinRAMFraction, 2, \
"Minimum fraction (1/n) of real memory used for maximum heap " \
"size on systems with small physical memory size. " \
"Deprecated, use MinRAMPercentage instead") \
range(1, max_uintx)
julong reasonable_max = (julong)((phys_mem * MaxRAMPercentage) / 100);
const julong reasonable_min = (julong)((phys_mem * MinRAMPercentage) / 100);
if (reasonable_min < MaxHeapSize) {
// Small physical memory, so use a minimum fraction of it for the heap
reasonable_max = reasonable_min;
} else {
// Not-small physical memory, so require a heap at least
// as large as MaxHeapSize
reasonable_max = MAX2(reasonable_max, (julong)MaxHeapSize);
}
product(size_t, MaxHeapSize, ScaleForWordSize(96*M), \
"Maximum heap size (in bytes)") \
constraint(MaxHeapSizeConstraintFunc,AfterErgo)
MaxHeapSize默认96m,所以现在的机型上不会出现reasonable_min的情况,所以看到的heap都是四分之一。
if (InitialHeapSize == 0 || MinHeapSize == 0) {
julong reasonable_minimum = (julong)(OldSize + NewSize);
reasonable_minimum = MIN2(reasonable_minimum, (julong)MaxHeapSize);
reasonable_minimum = limit_heap_by_allocatable_memory(reasonable_minimum);
if (InitialHeapSize == 0) {
julong reasonable_initial = (julong)((phys_mem * InitialRAMPercentage) / 100);
reasonable_initial = limit_heap_by_allocatable_memory(reasonable_initial);
reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, (julong)MinHeapSize);
reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize);
FLAG_SET_ERGO(InitialHeapSize, (size_t)reasonable_initial);
log_trace(gc, heap)(" Initial heap size " SIZE_FORMAT, InitialHeapSize);
}
// If the minimum heap size has not been set (via -Xms or -XX:MinHeapSize),
// synchronize with InitialHeapSize to avoid errors with the default value.
if (MinHeapSize == 0) {
FLAG_SET_ERGO(MinHeapSize, MIN2((size_t)reasonable_minimum, InitialHeapSize));
log_trace(gc, heap)(" Minimum heap size " SIZE_FORMAT, MinHeapSize);
}
if (FLAG_IS_DEFAULT(InitialRAMPercentage) &&
!FLAG_IS_DEFAULT(InitialRAMFraction))
InitialRAMPercentage = 100.0 / InitialRAMFraction;
product(uintx, InitialRAMFraction, 64, \
"Fraction (1/n) of real memory used for initial heap size. " \
"Deprecated, use InitialRAMPercentage instead") \
range(1, max_uintx)
JVM 会大概根据检测到的内存大小,设置最初启动时的堆大小为系统内存的 1/64;并将堆最大值,设置为系统内存的 1/4。
julong os::physical_memory() {
jlong phys_mem = 0;
if (OSContainer::is_containerized()) {
jlong mem_limit;
if ((mem_limit = OSContainer::memory_limit_in_bytes()) > 0) {
log_trace(os)("total container memory: " JLONG_FORMAT, mem_limit);
return mem_limit;
}
log_debug(os, container)("container memory limit %s: " JLONG_FORMAT ", using host value",
mem_limit == OSCONTAINER_ERROR ? "failed" : "unlimited", mem_limit);
}
phys_mem = Linux::physical_memory();
log_trace(os)("total system memory: " JLONG_FORMAT, phys_mem);
return phys_mem;
}
在容器的情况下physical_memory返回的是memory_limit_in_bytes。所以这个值会作为我们设置默认heap值的指标。
现有的问题
问题1
jmx getProcessCpuTime指标在使用share mode的时候,运行一段时间会返回-1。
目前这个bug已经在19,17,11上修复。但是jdk8的还没修复。pr还没有被review
https://github.com/openjdk/jdk8u-dev/pull/105
很有可能无法进入jdk8的分支。也就是说jdk8上想规避这个问题,最好就是不用share mode或者直接升级jdk。
问题2
当在容器环境下,jvm启动不检测xmx是否有效。jvm进程设置了xmx,但是内存默认是懒加载,所以不会里面占用那么多,但容器给不了那么多的资源,最后会在运行时被kill掉。如果改成提前加载的模式 -XX:+AlwaysPreTouch,在启动时就知道heap的内存是否足够。