Hotspot GC 源码分析

Hotspot GC 源码分析

JDK 版本 openjdk version “19-internal” 2022-09-20

内存管理

JVM 对于各块内存的管理,主要由以下函数控制:

malloc/free

allocation.hpp 定义了分配堆释放堆的函数:

char* AllocateHeap(size_t size, MEMFLAGS flags, const NativeCallStack& stack, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM);
char* AllocateHeap(size_t size, MEMFLAGS flags, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM);
char* ReallocateHeap(char *old, size_t size, MEMFLAGS flag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM);

void FreeHeap(void* p);

allocation.cpp 的具体实现中:

// allocate using malloc; will fail if no memory available
char* AllocateHeap(size_t size,
                   MEMFLAGS flags,
                   const NativeCallStack& stack,
                   AllocFailType alloc_failmode /* = AllocFailStrategy::EXIT_OOM*/) {
  char* p = (char*) os::malloc(size, flags, stack);
  if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) {
    vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "AllocateHeap");
  }
  return p;
}

void FreeHeap(void* p) {
  os::free(p);
}

os.cpp 中的实现:

void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {

  // Special handling for NMT preinit phase before arguments are parsed
  void* rc = NULL;
  if (NMTPreInit::handle_malloc(&rc, size)) {
    return rc;
  }

  DEBUG_ONLY(check_crash_protection());

  // On malloc(0), implementators of malloc(3) have the choice to return either
  // NULL or a unique non-NULL pointer. To unify libc behavior across our platforms
  // we chose the latter.
  size = MAX2((size_t)1, size);

  // For the test flag -XX:MallocMaxTestWords
  if (has_reached_max_malloc_test_peak(size)) {
    return NULL;
  }

  const size_t outer_size = size + MemTracker::overhead_per_malloc();

  void* const outer_ptr = ::malloc(outer_size);
  if (outer_ptr == NULL) {
    return NULL;
  }

  void* const inner_ptr = MemTracker::record_malloc((address)outer_ptr, size, memflags, stack);

  DEBUG_ONLY(::memset(inner_ptr, uninitBlockPad, size);)
  DEBUG_ONLY(break_if_ptr_caught(inner_ptr);)

  return inner_ptr;
}

void  os::free(void *memblock) {

  // Special handling for NMT preinit phase before arguments are parsed
  if (NMTPreInit::handle_free(memblock)) {
    return;
  }

  if (memblock == NULL) {
    return;
  }

  DEBUG_ONLY(break_if_ptr_caught(memblock);)

  // If NMT is enabled, this checks for heap overwrites, then de-accounts the old block.
  void* const old_outer_ptr = MemTracker::record_free(memblock);

  ::free(old_outer_ptr);
}

commit_memory

此函数在 os_linux.cpp 中的实现:

// NOTE: Linux kernel does not really reserve the pages for us.
//       All it does is to check if there are enough free pages
//       left at the time of mmap(). This could be a potential
//       problem.
int os::Linux::commit_memory_impl(char* addr, size_t size, bool exec) {
  int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
  uintptr_t res = (uintptr_t) ::mmap(addr, size, prot,
                                     MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);
  if (res != (uintptr_t) MAP_FAILED) {
    if (UseNUMAInterleaving) {
      numa_make_global(addr, size);
    }
    return 0;
  }

  int err = errno;  // save errno from mmap() call above

  if (!recoverable_mmap_error(err)) {
    warn_fail_commit_memory(addr, size, exec, err);
    vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "committing reserved memory.");
  }

  return err;
}

bool os::pd_commit_memory(char* addr, size_t size, bool exec) {
  return os::Linux::commit_memory_impl(addr, size, exec) == 0;
}

uncommit_memory

此函数在 os_linux.cpp 中的实现:

bool os::pd_uncommit_memory(char* addr, size_t size, bool exec) {
  uintptr_t res = (uintptr_t) ::mmap(addr, size, PROT_NONE,
                                     MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0);
  return res  != (uintptr_t) MAP_FAILED;
}

reserve_memory

此函数在 os_linux.cpp 中的实现:

char* os::pd_reserve_memory(size_t bytes, bool exec) {
  return anon_mmap(NULL, bytes);
}

// 'requested_addr' is only treated as a hint, the return value may or
// may not start from the requested address. Unlike Linux mmap(), this
// function returns NULL to indicate failure.
static char* anon_mmap(char* requested_addr, size_t bytes) {
  // MAP_FIXED is intentionally left out, to leave existing mappings intact.
  const int flags = MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS;

  // Map reserved/uncommitted pages PROT_NONE so we fail early if we
  // touch an uncommitted page. Otherwise, the read/write might
  // succeed if we have enough swap space to back the physical page.
  char* addr = (char*)::mmap(requested_addr, bytes, PROT_NONE, flags, -1, 0);

  return addr == MAP_FAILED ? NULL : addr;
}

release_memory

bool os::pd_release_memory(char* addr, size_t size) {
  return anon_munmap(addr, size);
}

static int anon_munmap(char * addr, size_t size) {
  return ::munmap(addr, size) == 0;
}

内存管理类

JVM 参数

JVM 参数的默认值定义在 gc_globals.hpp 文件中。

VirtualSpace

void VirtualSpace::shrink_by(size_t size) {
  os::uncommit_memory(aligned_upper_new_high, upper_needs, _executable);
}

MemoryPool

// memoryPool.hpp
class MemoryPool : public CHeapObj<mtInternal> {
  public:
    enum PoolType {
      Heap    = 1,
      NonHeap = 2
    };

  private:
    const char*      _name;
    PoolType         _type;
    size_t           _initial_size;
    size_t           _max_size;
    bool             _available_for_allocation; // Default is true
}

CHeapObj

CHeapObj 表示分配在 C-heap 上的对象,这类对象通过 free/malloc 函数管理内存,NMT 追踪内存使用:

template <MEMFLAGS F> class CHeapObj ALLOCATION_SUPER_CLASS_SPEC {
    public:
        ALWAYSINLINE void* operator new(size_t size) throw() {
            return (void*)AllocateHeap(size, F);
        }
        ALWAYSINLINE void* operator new[](size_t size) throw() {
            return (void*)AllocateHeap(size, F);
        }

        void  operator delete(void* p)     { FreeHeap(p); }
        void  operator delete [] (void* p) { FreeHeap(p); }
};

Thread

Thread 的内存是通过 mallocfree 函数来管理的:

// thread.cpp

// ======= Thread ========
void* Thread::allocate(size_t size, bool throw_excpt, MEMFLAGS flags) {
  return throw_excpt ? AllocateHeap(size, flags, CURRENT_PC)
                       : AllocateHeap(size, flags, CURRENT_PC, AllocFailStrategy::RETURN_NULL);
}

void Thread::operator delete(void* p) {
  FreeHeap(p);
}

GC 类

serial

class SerialHeap : public GenCollectedHeap {
private:
  MemoryPool* _eden_pool;
  MemoryPool* _survivor_pool;
  MemoryPool* _old_pool;
}

parallel

class ParallelScavengeHeap : public CollectedHeap {
 private:
  static PSYoungGen* _young_gen;
  static PSOldGen*   _old_gen;

  MemoryPool* _eden_pool;
  MemoryPool* _survivor_pool;
  MemoryPool* _old_pool;
}