当前位置: 首页 > article >正文

openjdk17 中 klass 数组 在元空间内存分配

在 OpenJDK 17 中,klass 对象(即 Java 类的元数据)的内存分配通常在元空间(Metaspace)中进行。元空间是 Java 堆外的一块内存区域,用于存储类的元数据。以下几个关键函数,它们共同参与了 klass 对象的内存分配过程:

  1. ConstantPool::allocate_resolved_klasses

    • 这个函数用于为 ConstantPool 中解析后的类条目分配内存。它创建了一个 Array<Klass*> 类型的数组,用于存储指向已解析类的指针。
  2. MetadataFactory::new_array

    • 这是一个模板函数,用于创建一个新的元数据数组。它调用 Array<T> 类的构造函数来分配内存,并返回一个指向新数组的指针。
  3. Array<T>::operator new

    • 这个模板函数是 new 操作符的重载版本,专门为元数据数组分配内存。它调用 Metaspace::allocate 来在元空间中分配内存。
  4. Metaspace::allocate

    • 这个函数是元空间内存分配的核心函数。它接受类加载器数据、请求的字大小、类型和线程指针作为参数,并返回一个指向分配的内存区域的指针。
  5. ClassLoaderMetaspace::allocate

    • 这个函数用于从类加载器的元空间中分配内存。它根据元数据类型(类或非类)选择正确的内存区域(类空间或非类空间)进行分配。
  6. MetaspaceArena::allocate

    • 这个函数尝试从当前的 MetaspaceArena 中分配内存。如果当前块太小或不足以容纳请求的大小,它会尝试扩展当前块或分配一个新的块。
  7. Metachunk::allocate

    • 这个函数用于在 Metachunk 中分配内存。Metachunk 是元空间中用于存储元数据的一块内存区域。

这些函数共同构成了 OpenJDK 中元空间分配的框架,它们确保了类的元数据能够在堆外内存中被有效地管理和回收。通过这种方式,OpenJDK 减少了 Full GC 的频率,提高了 JVM 的性能和稳定性。

##C++源代码

void ConstantPool::allocate_resolved_klasses(ClassLoaderData* loader_data, int num_klasses, TRAPS) {
  // A ConstantPool can't possibly have 0xffff valid class entries,
  // because entry #0 must be CONSTANT_Invalid, and each class entry must refer to a UTF8
  // entry for the class's name. So at most we will have 0xfffe class entries.
  // This allows us to use 0xffff (ConstantPool::_temp_resolved_klass_index) to indicate
  // UnresolvedKlass entries that are temporarily created during class redefinition.
  assert(num_klasses < CPKlassSlot::_temp_resolved_klass_index, "sanity");
  assert(resolved_klasses() == NULL, "sanity");
  Array<Klass*>* rk = MetadataFactory::new_array<Klass*>(loader_data, num_klasses, CHECK);
  set_resolved_klasses(rk);
}
template <typename T>
  static Array<T>* new_array(ClassLoaderData* loader_data, int length, TRAPS) {
    // The "true" argument is because all metadata arrays are read only when
    // dumped to the shared archive
    return new (loader_data, length, THREAD) Array<T>(length);
  }
template <typename T>
inline void* Array<T>::operator new(size_t size, ClassLoaderData* loader_data, int length, TRAPS) throw() {
  size_t word_size = Array::size(length);
  return (void*) Metaspace::allocate(loader_data, word_size,
                                     MetaspaceObj::array_type(sizeof(T)), THREAD);
}
MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
                              MetaspaceObj::Type type, TRAPS) {

  if (HAS_PENDING_EXCEPTION) {
    assert(false, "Should not allocate with exception pending");
    return NULL;  // caller does a CHECK_NULL too
  }

  MetaWord* result = allocate(loader_data, word_size, type);

  if (result == NULL) {
    MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType;
    tracer()->report_metaspace_allocation_failure(loader_data, word_size, type, mdtype);

    // Allocation failed.
    if (is_init_completed()) {
      // Only start a GC if the bootstrapping has completed.
      // Try to clean out some heap memory and retry. This can prevent premature
      // expansion of the metaspace.
      result = Universe::heap()->satisfy_failed_metadata_allocation(loader_data, word_size, mdtype);
    }

    if (result == NULL) {
      report_metadata_oome(loader_data, word_size, type, mdtype, THREAD);
      assert(HAS_PENDING_EXCEPTION, "sanity");
      return NULL;
    }

    // Zero initialize.
    Copy::fill_to_words((HeapWord*)result, word_size, 0);

    log_trace(metaspace)("Metaspace::allocate: type %d return " PTR_FORMAT ".", (int)type, p2i(result));
  }

  return result;
}
MetaWord* Metaspace::allocate(ClassLoaderData* loader_data, size_t word_size,
                              MetaspaceObj::Type type) {
  assert(word_size <= Metaspace::max_allocation_word_size(),
         "allocation size too large (" SIZE_FORMAT ")", word_size);

  assert(loader_data != NULL, "Should never pass around a NULL loader_data. "
        "ClassLoaderData::the_null_class_loader_data() should have been used.");

  MetadataType mdtype = (type == MetaspaceObj::ClassType) ? ClassType : NonClassType;

  // Try to allocate metadata.
  MetaWord* result = loader_data->metaspace_non_null()->allocate(word_size, mdtype);

  if (result != NULL) {
    // Zero initialize.
    Copy::fill_to_words((HeapWord*)result, word_size, 0);

    log_trace(metaspace)("Metaspace::allocate: type %d return " PTR_FORMAT ".", (int)type, p2i(result));
  }

  return result;
}

// Allocate word_size words from Metaspace.
MetaWord* ClassLoaderMetaspace::allocate(size_t word_size, Metaspace::MetadataType mdType) {
  if (Metaspace::is_class_space_allocation(mdType)) {
    return class_space_arena()->allocate(word_size);
  } else {
    return non_class_space_arena()->allocate(word_size);
  }
}

MetaWord* MetaspaceArena::allocate(size_t requested_word_size) {
  MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);
  UL2(trace, "requested " SIZE_FORMAT " words.", requested_word_size);

  MetaWord* p = NULL;
  const size_t raw_word_size = get_raw_word_size_for_requested_word_size(requested_word_size);

  // 1) Attempt to allocate from the free blocks list
  //    (Note: to reduce complexity, deallocation handling is disabled if allocation guards
  //     are enabled, see Settings::ergo_initialize())
  if (Settings::handle_deallocations() && _fbl != NULL && !_fbl->is_empty()) {
    p = _fbl->remove_block(raw_word_size);
    if (p != NULL) {
      DEBUG_ONLY(InternalStats::inc_num_allocs_from_deallocated_blocks();)
      UL2(trace, "taken from fbl (now: %d, " SIZE_FORMAT ").",
          _fbl->count(), _fbl->total_size());
      // Note: Space which is kept in the freeblock dictionary still counts as used as far
      //  as statistics go; therefore we skip the epilogue in this function to avoid double
      //  accounting.
      return p;
    }
  }

  bool current_chunk_too_small = false;
  bool commit_failure = false;

  if (current_chunk() != NULL) {

    // 2) Attempt to satisfy the allocation from the current chunk.

    // If the current chunk is too small to hold the requested size, attempt to enlarge it.
    // If that fails, retire the chunk.
    if (current_chunk()->free_words() < raw_word_size) {
      if (!attempt_enlarge_current_chunk(raw_word_size)) {
        current_chunk_too_small = true;
      } else {
        DEBUG_ONLY(InternalStats::inc_num_chunks_enlarged();)
        UL(debug, "enlarged chunk.");
      }
    }

    // Commit the chunk far enough to hold the requested word size. If that fails, we
    // hit a limit (either GC threshold or MaxMetaspaceSize). In that case retire the
    // chunk.
    if (!current_chunk_too_small) {
      if (!current_chunk()->ensure_committed_additional(raw_word_size)) {
        UL2(info, "commit failure (requested size: " SIZE_FORMAT ")", raw_word_size);
        commit_failure = true;
      }
    }

    // Allocate from the current chunk. This should work now.
    if (!current_chunk_too_small && !commit_failure) {
      p = current_chunk()->allocate(raw_word_size);
      assert(p != NULL, "Allocation from chunk failed.");
    }
  }

  if (p == NULL) {
    // If we are here, we either had no current chunk to begin with or it was deemed insufficient.
    assert(current_chunk() == NULL ||
           current_chunk_too_small || commit_failure, "Sanity");

    Metachunk* new_chunk = allocate_new_chunk(raw_word_size);
    if (new_chunk != NULL) {
      UL2(debug, "allocated new chunk " METACHUNK_FORMAT " for requested word size " SIZE_FORMAT ".",
          METACHUNK_FORMAT_ARGS(new_chunk), requested_word_size);

      assert(new_chunk->free_below_committed_words() >= raw_word_size, "Sanity");
      if (Settings::new_chunks_are_fully_committed()) {
        assert(new_chunk->is_fully_committed(), "Chunk should be fully committed.");
      }

      // We have a new chunk. Before making it the current chunk, retire the old one.
      if (current_chunk() != NULL) {
        salvage_chunk(current_chunk());
        DEBUG_ONLY(InternalStats::inc_num_chunks_retired();)
      }

      _chunks.add(new_chunk);

      // Now, allocate from that chunk. That should work.
      p = current_chunk()->allocate(raw_word_size);
      assert(p != NULL, "Allocation from chunk failed.");
    } else {
      UL2(info, "failed to allocate new chunk for requested word size " SIZE_FORMAT ".", requested_word_size);
    }
  }

#ifdef ASSERT
  // When using allocation guards, establish a prefix.
  if (p != NULL && Settings::use_allocation_guard()) {
    p = establish_prefix(p, raw_word_size);
  }
#endif

  if (p == NULL) {
    InternalStats::inc_num_allocs_failed_limit();
  } else {
    DEBUG_ONLY(InternalStats::inc_num_allocs();)
    _total_used_words_counter->increment_by(raw_word_size);
  }

  SOMETIMES(verify_locked();)

  if (p == NULL) {
    UL(info, "allocation failed, returned NULL.");
  } else {
    UL2(trace, "after allocation: %u chunk(s), current:" METACHUNK_FULL_FORMAT,
        _chunks.count(), METACHUNK_FULL_FORMAT_ARGS(current_chunk()));
    UL2(trace, "returning " PTR_FORMAT ".", p2i(p));
  }
  return p;
}
MetaWord* Metachunk::allocate(size_t request_word_size) {
  // Caller must have made sure this works
  assert(free_words() >= request_word_size, "Chunk too small.");
  assert(free_below_committed_words() >= request_word_size, "Chunk not committed.");
  MetaWord* const p = top();
  _used_words += request_word_size;
  SOMETIMES(verify();)
  return p;
}

##gdb调试栈

#0  metaspace::Metachunk::allocate (this=0x7ffff00c3a20, request_word_size=76) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/memory/metaspace/metachunk.cpp:169
#1  0x00007ffff67a99d7 in metaspace::MetaspaceArena::allocate (this=0x7ffff00d20f0, requested_word_size=76)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/memory/metaspace/metaspaceArena.cpp:278
#2  0x00007ffff5fe6ead in ClassLoaderMetaspace::allocate (this=0x7ffff00d0410, word_size=76, mdType=Metaspace::NonClassType)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/memory/classLoaderMetaspace.cpp:96
#3  0x00007ffff67a7b07 in Metaspace::allocate (loader_data=0x7ffff00c6180, word_size=76, type=MetaspaceObj::TypeArrayU8Type)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/memory/metaspace.cpp:888
#4  0x00007ffff67a7bf4 in Metaspace::allocate (loader_data=0x7ffff00c6180, word_size=76, type=MetaspaceObj::TypeArrayU8Type, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/memory/metaspace.cpp:908
#5  0x00007ffff6075e7f in Array<Klass*>::operator new (size=16, loader_data=0x7ffff00c6180, length=75, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/oops/array.inline.hpp:36
#6  0x00007ffff6075a22 in MetadataFactory::new_array<Klass*> (loader_data=0x7ffff00c6180, length=75, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/memory/metadataFactory.hpp:40
#7  0x00007ffff606bac7 in ConstantPool::allocate_resolved_klasses (this=0x7fffd9820c48, loader_data=0x7ffff00c6180, num_klasses=75, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/oops/constantPool.cpp:212
#8  0x00007ffff5fb05da in ClassFileParser::parse_constant_pool (this=0x7ffff7bfddd0, stream=0x7ffff003c240, cp=0x7fffd9820c48, length=1098, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/classFileParser.cpp:607
#9  0x00007ffff5fc1fe8 in ClassFileParser::parse_stream (this=0x7ffff7bfddd0, stream=0x7ffff003c240, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/classFileParser.cpp:5720
#10 0x00007ffff5fc179d in ClassFileParser::ClassFileParser (this=0x7ffff7bfddd0, stream=0x7ffff003c240, name=0x7fffe0498220, loader_data=0x7ffff00c6180, cl_info=0x7ffff7bfe000,
    pub_level=ClassFileParser::BROADCAST, __the_thread__=0x7ffff0028920) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/classFileParser.cpp:5590
#11 0x00007ffff66339a1 in KlassFactory::create_from_stream (stream=0x7ffff003c240, name=0x7fffe0498220, loader_data=0x7ffff00c6180, cl_info=..., __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/klassFactory.cpp:199
#12 0x00007ffff5fd2471 in ClassLoader::load_class (name=0x7fffe0498220, search_append_only=false, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/classLoader.cpp:1222
#13 0x00007ffff6b10a5a in SystemDictionary::load_instance_class_impl (class_name=0x7fffe0498220, class_loader=..., __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/systemDictionary.cpp:1290
#14 0x00007ffff6b10e35 in SystemDictionary::load_instance_class (name_hash=1500110387, name=0x7fffe0498220, class_loader=..., __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/systemDictionary.cpp:1356
#15 0x00007ffff6b0eefd in SystemDictionary::resolve_instance_class_or_null (name=0x7fffe0498220, class_loader=..., protection_domain=..., __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/systemDictionary.cpp:724
#16 0x00007ffff6b0da82 in SystemDictionary::resolve_instance_class_or_null_helper (class_name=0x7fffe0498220, class_loader=..., protection_domain=...,
    __the_thread__=0x7ffff0028920) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/systemDictionary.cpp:295
#17 0x00007ffff6b0d928 in SystemDictionary::resolve_or_null (class_name=0x7fffe0498220, class_loader=..., protection_domain=..., __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/systemDictionary.cpp:278
#18 0x00007ffff6b0d86b in SystemDictionary::resolve_or_fail (class_name=0x7fffe0498220, class_loader=..., protection_domain=..., throw_error=true, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/systemDictionary.cpp:264
#19 0x00007ffff5da8a1a in SystemDictionary::resolve_or_fail (class_name=0x7fffe0498220, throw_error=true, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/systemDictionary.hpp:100
#20 0x00007ffff6bf767c in vmClasses::resolve (id=vmClassID::ClassLoader_klass_knum, __the_thread__=0x7ffff0028920)
    at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/vmClasses.cpp:99
#21 0x00007ffff6bf777a in vmClasses::resolve_until (limit_id=vmClassID::SoftReference_klass_knum, start_id=@0x7ffff7bfe8f0: vmClassID::Cloneable_klass_knum,
    __the_thread__=0x7ffff0028920) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/vmClasses.cpp:108
#22 0x00007ffff6bf817e in vmClasses::resolve_through (last_id=vmClassID::Reference_klass_knum, start_id=@0x7ffff7bfe8f0: vmClassID::Cloneable_klass_knum,
    __the_thread__=0x7ffff0028920) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/vmClasses.hpp:64
#23 0x00007ffff6bf7a07 in vmClasses::resolve_all (__the_thread__=0x7ffff0028920) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/vmClasses.cpp:168
#24 0x00007ffff6b11cf6 in SystemDictionary::initialize (__the_thread__=0x7ffff0028920) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/classfile/systemDictionary.cpp:1654
#25 0x00007ffff6b96cbf in Universe::genesis (__the_thread__=0x7ffff0028920) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/memory/universe.cpp:335
#26 0x00007ffff6b99117 in universe2_init () at /home/yym/openjdk17/jdk17-master/src/hotspot/share/memory/universe.cpp:928
#27 0x00007ffff633fe73 in init_globals () at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/init.cpp:134
#28 0x00007ffff6b610b7 in Threads::create_vm (args=0x7ffff7bfed50, canTryAgain=0x7ffff7bfec5b) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/runtime/thread.cpp:2852
#29 0x00007ffff644f775 in JNI_CreateJavaVM_inner (vm=0x7ffff7bfeda8, penv=0x7ffff7bfedb0, args=0x7ffff7bfed50) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/prims/jni.cpp:3624
#30 0x00007ffff644fac1 in JNI_CreateJavaVM (vm=0x7ffff7bfeda8, penv=0x7ffff7bfedb0, args=0x7ffff7bfed50) at /home/yym/openjdk17/jdk17-master/src/hotspot/share/prims/jni.cpp:3712
#31 0x00007ffff7facd29 in InitializeJVM (pvm=0x7ffff7bfeda8, penv=0x7ffff7bfedb0, ifn=0x7ffff7bfee00) at /home/yym/openjdk17/jdk17-master/src/java.base/share/native/libjli/java.c:1541
#32 0x00007ffff7fa9623 in JavaMain (_args=0x7fffffffaed0) at /home/yym/openjdk17/jdk17-master/src/java.base/share/native/libjli/java.c:415
#33 0x00007ffff7fb08ab in ThreadJavaMain (args=0x7fffffffaed0) at /home/yym/openjdk17/jdk17-master/src/java.base/unix/native/libjli/java_md.c:651
#34 0x00007ffff7c94ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#35 0x00007ffff7d26850 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81


http://www.kler.cn/a/451802.html

相关文章:

  • 图神经网络_图嵌入_SDNE
  • git push origin HEAD:refs/for/分支名
  • SpringCloud 系列教程:微服务的未来(二)Mybatis-Plus的条件构造器、自定义SQL、Service接口基本用法
  • 教育行业 UI 设计基础篇:简洁直观的风格打造
  • InnoDB引擎的内存结构
  • 778-批量删除指定文件夹下指定格式文件(包含子孙文件夹下的)
  • EMS从0到1之数据采集
  • 08. 基于docker-compose部署LNMP架构
  • Debug的使用
  • 19、vue3组件通信
  • STM32文件详解
  • 从 GitLab.com 到 JihuLab.com 的迁移指南
  • leetcode之hot100---19删除链表的第N个节点(C++)
  • GitLab 将停止为中国区用户提供服务,60天迁移期如何应对? | LeetTalk Daily
  • 【NLP高频面题 - 高效微调篇】什么是提示微调?
  • 全国硕士研究生入学考试(考研)备考要点之备考原则
  • GMV 含义
  • 【R语言遥感技术】“R+遥感”的水环境综合评价方法
  • 接口请求中调试可以看到Origin,其具体的作用
  • 【文档搜索引擎】缓冲区优化和索引模块小结
  • 框架专题:设计模式
  • mvn install:install-file jar 打入本地仓库
  • 虚拟机桥接模式
  • Spark和Hive的联系
  • 【视觉惯性SLAM:SLAM中常用的数学基础知识】
  • BOM清单在制造企业运营中的全方位作用解析