< prev index next >

src/share/vm/memory/metaspaceShared.cpp

Print this page

@@ -69,19 +69,21 @@
 bool MetaspaceShared::_remapped_readwrite = false;
 address MetaspaceShared::_cds_i2i_entry_code_buffers = NULL;
 size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0;
 size_t MetaspaceShared::_core_spaces_size = 0;
 
-// The CDS archive is divided into 6 regions:
+// The CDS archive is divided into the following regions:
 //     mc - misc code (the method entry trampolines)
 //     rw - read-write metadata
 //     ro - read-only metadata and read-only tables
 //     md - misc data (the c++ vtables)
-//     od - other data (original class files)
-//     st - shared strings
+//     od - optional data (original class files)
 //
-// Except for the st region, the other 5 regions are linearly allocated, starting from
+//     s0 - shared strings #0
+//     s1 - shared strings #1 (may be empty)
+//
+// Except for the s0/s1 regions, the other 5 regions are linearly allocated, starting from
 // SharedBaseAddress, in the order of mc->rw->ro->md->od. The size of these 5 regions
 // are page-aligned, and there's no gap between any consecutive regions.
 //
 // These 5 regions are populated in the following steps:
 // [1] All classes are loaded in MetaspaceShared::preload_classes(). All metadata are

@@ -92,11 +94,11 @@
 // [4] SymbolTable, StringTable, SystemDictionary, and a few other read-only data
 //     are copied into the ro region as read-only tables.
 // [5] C++ vtables are copied into the md region.
 // [6] Original class files are copied into the od region.
 //
-// The st region is populated inside MetaspaceShared::dump_string_and_symbols. Its
+// The s0/s1 regions are populated inside MetaspaceShared::dump_string_and_symbols. Their
 // layout is independent of the other 5 regions.
 
 class DumpRegion {
 private:
   const char* _name;

@@ -119,19 +121,19 @@
 
 public:
   DumpRegion(const char* name) : _name(name), _base(NULL), _top(NULL), _end(NULL), _is_packed(false) {}
 
   char* allocate(size_t num_bytes, size_t alignment=BytesPerWord) {
-    char* p = (char*)align_ptr_up(_top, alignment);
-    char* newtop = p + align_size_up(num_bytes, alignment);
+    char* p = (char*)align_up(_top, alignment);
+    char* newtop = p + align_up(num_bytes, alignment);
     expand_top_to(newtop);
     memset(p, 0, newtop - p);
     return p;
   }
 
   void append_intptr_t(intptr_t n) {
-    assert(is_ptr_aligned(_top, sizeof(intptr_t)), "bad alignment");
+    assert(is_aligned(_top, sizeof(intptr_t)), "bad alignment");
     intptr_t *p = (intptr_t*)_top;
     char* newtop = _top + sizeof(intptr_t);
     expand_top_to(newtop);
     *p = n;
   }

@@ -145,11 +147,13 @@
   bool is_allocatable() const {
     return !is_packed() && _base != NULL;
   }
 
   double perc(size_t used, size_t total) const {
-    if (total == 0) {total = 1;}
+    if (total == 0) {
+      total = 1;
+    }
     return used / double(total) * 100.0;
   }
 
   void print(size_t total_bytes) const {
     tty->print_cr("%s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT,

@@ -175,11 +179,11 @@
     _end = e;
   }
 
   void pack(DumpRegion* next = NULL) {
     assert(!is_packed(), "sanity");
-    _end = (char*)align_ptr_up(_top, Metaspace::reserve_alignment());
+    _end = (char*)align_up(_top, Metaspace::reserve_alignment());
     _is_packed = true;
     if (next != NULL) {
       next->_base = next->_top = this->_end;
       next->_end = MetaspaceShared::shared_rs()->end();
     }

@@ -187,12 +191,12 @@
   bool contains(char* p) {
     return base() <= p && p < top();
   }
 };
 
-DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md");
-DumpRegion _st_region("st"), _od_region("od");
+DumpRegion _mc_region("mc"), _ro_region("ro"), _rw_region("rw"), _md_region("md"), _od_region("od");
+DumpRegion _s0_region("s0"), _s1_region("s1");
 
 char* MetaspaceShared::misc_code_space_alloc(size_t num_bytes) {
   return _mc_region.allocate(num_bytes);
 }
 

@@ -201,18 +205,18 @@
 }
 
 void MetaspaceShared::initialize_shared_rs() {
   const size_t reserve_alignment = Metaspace::reserve_alignment();
   bool large_pages = false; // No large pages when dumping the CDS archive.
-  char* shared_base = (char*)align_ptr_up((char*)SharedBaseAddress, reserve_alignment);
+  char* shared_base = (char*)align_up((char*)SharedBaseAddress, reserve_alignment);
 
 #ifdef _LP64
   const uint64_t UnscaledClassSpaceMax = (uint64_t(max_juint) + 1);
-  const size_t cds_total = align_size_down(UnscaledClassSpaceMax, reserve_alignment);
+  const size_t cds_total = align_down(UnscaledClassSpaceMax, reserve_alignment);
 #else
   // We don't support archives larger than 256MB on 32-bit due to limited virtual address space.
-  size_t cds_total = align_size_down(256*M, reserve_alignment);
+  size_t cds_total = align_down(256*M, reserve_alignment);
 #endif
 
   // First try to reserve the space at the specified SharedBaseAddress.
   _shared_rs = ReservedSpace(cds_total, reserve_alignment, large_pages, shared_base);
   if (_shared_rs.is_reserved()) {

@@ -235,13 +239,13 @@
   //   then the RO parts.
 
   assert(UseCompressedOops && UseCompressedClassPointers,
       "UseCompressedOops and UseCompressedClassPointers must be set");
 
-  size_t max_archive_size = align_size_down(cds_total * 3 / 4, reserve_alignment);
+  size_t max_archive_size = align_down(cds_total * 3 / 4, reserve_alignment);
   ReservedSpace tmp_class_space = _shared_rs.last_part(max_archive_size);
-  CompressedClassSpaceSize = align_size_down(tmp_class_space.size(), reserve_alignment);
+  CompressedClassSpaceSize = align_down(tmp_class_space.size(), reserve_alignment);
   _shared_rs = _shared_rs.first_part(max_archive_size);
 
   // Set up compress class pointers.
   Universe::set_narrow_klass_base((address)_shared_rs.base());
   if (UseAOT || cds_total > UnscaledClassSpaceMax) {

@@ -285,14 +289,17 @@
 
   size_t commit = MAX2(min_bytes, preferred_bytes);
   assert(commit <= uncommitted, "sanity");
 
   bool result = _shared_vs.expand_by(commit, false);
-  assert(result, "Failed to commit memory");
+  if (!result) {
+    vm_exit_during_initialization(err_msg("Failed to expand shared space to " SIZE_FORMAT " bytes",
+                                          need_committed_size));
+  }
 
-  log_info(cds)("Expanding shared spaces by %7d bytes [total %8d bytes ending at %p]",
-                int(commit), int(_shared_vs.actual_committed_size()), _shared_vs.high());
+  log_info(cds)("Expanding shared spaces by " SIZE_FORMAT_W(7) " bytes [total " SIZE_FORMAT_W(9)  " bytes ending at %p]",
+                commit, _shared_vs.actual_committed_size(), _shared_vs.high());
 }
 
 // Read/write a data stream for restoring/preserving metadata pointers and
 // miscellaneous data from/to the shared archive file.
 

@@ -495,11 +502,11 @@
 
 template <class T> CppVtableInfo* CppVtableCloner<T>::_info = NULL;
 
 template <class T>
 intptr_t* CppVtableCloner<T>::allocate(const char* name) {
-  assert(is_ptr_aligned(_md_region.top(), sizeof(intptr_t)), "bad alignment");
+  assert(is_aligned(_md_region.top(), sizeof(intptr_t)), "bad alignment");
   int n = get_vtable_length(name);
   _info = (CppVtableInfo*)_md_region.allocate(CppVtableInfo::byte_size(n), sizeof(intptr_t));
   _info->set_vtable_size(n);
 
   intptr_t* p = clone_vtable(name, _info);

@@ -733,10 +740,14 @@
     int which = (read_only) ? RO : RW;
     _counts[which][type] ++;
     _bytes [which][type] += byte_size;
   }
 
+  void record_other_type(int byte_size, bool read_only) {
+    int which = (read_only) ? RO : RW;
+    _bytes [which][OtherType] += byte_size;
+  }
   void print_stats(int ro_all, int rw_all, int mc_all, int md_all);
 };
 
 void DumpAllocStats::print_stats(int ro_all, int rw_all, int mc_all, int md_all) {
   // Calculate size of data that was not allocated by Metaspace::allocate()

@@ -780,11 +791,11 @@
 
   ResourceMark rm;
   LogMessage(cds) msg;
   stringStream info_stream;
 
-  info_stream.print_cr("Detailed metadata info (rw includes md and mc):");
+  info_stream.print_cr("Detailed metadata info (excluding od/st regions; rw stats include md/mc regions):");
   info_stream.print_cr("%s", hdr);
   info_stream.print_cr("%s", sep);
   for (int type = 0; type < int(_number_of_types); type ++) {
     const char *name = type_name((Type)type);
     int ro_count = _counts[RO][type];

@@ -820,11 +831,11 @@
   info_stream.print_cr(fmt_stats, "Total",
                        all_ro_count, all_ro_bytes, all_ro_perc,
                        all_rw_count, all_rw_bytes, all_rw_perc,
                        all_count, all_bytes, all_perc);
 
-//assert(all_ro_bytes == ro_all, "everything should have been counted");
+  assert(all_ro_bytes == ro_all, "everything should have been counted");
   assert(all_rw_bytes == rw_all, "everything should have been counted");
 
   msg.info("%s", info_stream.as_string());
 #undef fmt_stats
 }

@@ -835,10 +846,11 @@
 private:
   GrowableArray<MemRegion> *_string_regions;
 
   void dump_string_and_symbols();
   char* dump_read_only_tables();
+  void print_region_stats();
 public:
 
   VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
   void doit();   // outline because gdb sucks
   static void write_region(FileMapInfo* mapinfo, int region, DumpRegion* space, bool read_only,  bool allow_exec);

@@ -888,38 +900,45 @@
   }
   typedef ResourceHashtable<
       address, address,
       ArchiveCompactor::my_hash,   // solaris compiler doesn't like: primitive_hash<address>
       ArchiveCompactor::my_equals, // solaris compiler doesn't like: primitive_equals<address>
-      16384, ResourceObj::C_HEAP> MyTable;
-  static MyTable* _new_loc_table;
+      16384, ResourceObj::C_HEAP> RelocationTable;
+  static RelocationTable* _new_loc_table;
 
 public:
   static void initialize() {
     _alloc_stats = new(ResourceObj::C_HEAP, mtInternal)DumpAllocStats;
-    _new_loc_table = new(ResourceObj::C_HEAP, mtInternal)MyTable;
+    _new_loc_table = new(ResourceObj::C_HEAP, mtInternal)RelocationTable;
   }
   static DumpAllocStats* alloc_stats() {
     return _alloc_stats;
   }
 
   static void allocate(MetaspaceClosure::Ref* ref, bool read_only) {
     address obj = ref->obj();
     int bytes = ref->size() * BytesPerWord;
     char* p;
     size_t alignment = BytesPerWord;    
+    char* oldtop;
+    char* newtop;
+
     if (read_only) {
+      oldtop = _ro_region.top();
       p = _ro_region.allocate(bytes, alignment);
+      newtop = _ro_region.top();
     } else {
+      oldtop = _rw_region.top();
       p = _rw_region.allocate(bytes, alignment);
+      newtop = _rw_region.top();
     }
     memcpy(p, obj, bytes);
     bool isnew = _new_loc_table->put(obj, (address)p);
     assert(isnew, "must be");
     log_trace(cds)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(obj), p2i(p), bytes);
 
-    _alloc_stats->record(ref->msotype(), bytes, read_only);
+    _alloc_stats->record(ref->msotype(), int(newtop - oldtop), read_only);
     if (ref->msotype() == MetaspaceObj::SymbolType) {
       uintx delta = MetaspaceShared::object_delta(p);
       if (delta > MAX_SHARED_DELTA) {
         // This is just a sanity check and should not appear in any real world usage. This
         // happens only if you allocate more than 2GB of Symbols and would require

@@ -1040,16 +1059,16 @@
     // cleanup
     _ssc = NULL;
   }
 
   // We must relocate the System::_well_known_klasses only after we have copied the
-  // strings in during dump_string_and_symbols(): during the copy, we operate on old
+  // strings in during dump_string_and_symbols(): during the string copy, we operate on old
   // String objects which assert that their klass is the old
   // SystemDictionary::String_klass().
   static void relocate_well_known_klasses() {
     {
-      tty->print_cr("Relocating _well_known_klasses[] ... ");
+      tty->print_cr("Relocating SystemDictionary::_well_known_klasses[] ... ");
       ResourceMark rm;
       RefRelocator ext_reloc;
       SystemDictionary::well_known_klasses_do(&ext_reloc);
     }
     // NOTE: after this point, we shouldn't have any globals that can reach the old

@@ -1088,11 +1107,11 @@
   }
 };
 
 DumpAllocStats* ArchiveCompactor::_alloc_stats;
 SortedSymbolClosure* ArchiveCompactor::_ssc;
-ArchiveCompactor::MyTable* ArchiveCompactor::_new_loc_table;
+ArchiveCompactor::RelocationTable* ArchiveCompactor::_new_loc_table;
 
 void VM_PopulateDumpSharedSpace::write_region(FileMapInfo* mapinfo, int region_idx,
                                               DumpRegion* dump_region, bool read_only,  bool allow_exec) {
   mapinfo->write_region(region_idx, dump_region->base(), dump_region->used(), read_only, allow_exec);
 }

@@ -1104,19 +1123,15 @@
   NOT_PRODUCT(StringTable::verify());
   SymbolTable::write_to_archive();
 
   // The string space has maximum two regions. See FileMapInfo::write_string_regions() for details.
   _string_regions = new GrowableArray<MemRegion>(2);
-  size_t shared_string_bytes = 0;
-  StringTable::write_to_archive(_string_regions, &shared_string_bytes);
-  char* st_base = _string_regions->is_empty() ? NULL : (char*)_string_regions->first().start();
-  char* st_top = st_base + shared_string_bytes;
-  _st_region.init(st_base, st_top, st_top);
-  _st_region.pack();
+  StringTable::write_to_archive(_string_regions);
 }
 
 char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
+  char* oldtop = _ro_region.top();
   // Reorder the system dictionary. Moving the symbols affects
   // how the hash table indices are calculated.
   SystemDictionary::reorder_dictionary_for_sharing();
   NOT_PRODUCT(SystemDictionary::verify();)
 

@@ -1130,10 +1145,12 @@
 
   // Write the other data to the output array.
   WriteClosure wc(&_ro_region);
   MetaspaceShared::serialize(&wc);
 
+  char* newtop = _ro_region.top();
+  ArchiveCompactor::alloc_stats()->record_other_type(int(newtop - oldtop), true);
   return buckets_top;
 }
 
 void VM_PopulateDumpSharedSpace::doit() {
   Thread* THREAD = VMThread::vm_thread();

@@ -1207,32 +1224,13 @@
   _od_region.pack();
 
   // The 5 core spaces are allocated consecutively mc->rw->ro->md->od, so there total size
   // is just the spaces between the two ends.
   size_t core_spaces_size = _od_region.end() - _mc_region.base();
-  assert(core_spaces_size == (size_t)align_size_up(core_spaces_size, Metaspace::reserve_alignment()),
+  assert(core_spaces_size == (size_t)align_up(core_spaces_size, Metaspace::reserve_alignment()),
          "should already be aligned");
 
-  // Print statistics of all the regions
-  const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() +
-                                _mc_region.reserved() + _md_region.reserved() +
-                                _st_region.reserved() + _od_region.reserved();
-  const size_t total_bytes = _ro_region.used() + _rw_region.used() +
-                             _mc_region.used() + _md_region.used() +
-                             _st_region.used() + _od_region.used();
-  const double total_u_perc = total_bytes / double(total_reserved) * 100.0;
-
-  _mc_region.print(total_reserved);
-  _rw_region.print(total_reserved);
-  _ro_region.print(total_reserved);
-  _md_region.print(total_reserved);
-  _st_region.print(total_reserved);
-  _od_region.print(total_reserved);
-
-  tty->print_cr("total   : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
-                 total_bytes, total_reserved, total_u_perc);
-
   // During patching, some virtual methods may be called, so at this point
   // the vtables must contain valid methods (as filled in by CppVtableCloner::allocate).
   MetaspaceShared::patch_cpp_vtable_pointers();
 
   // The vtable clones contain addresses of the current process.

@@ -1247,10 +1245,13 @@
   mapinfo->set_misc_data_patching_start(vtbl_list);
   mapinfo->set_cds_i2i_entry_code_buffers(MetaspaceShared::cds_i2i_entry_code_buffers());
   mapinfo->set_cds_i2i_entry_code_buffers_size(MetaspaceShared::cds_i2i_entry_code_buffers_size());
   mapinfo->set_core_spaces_size(core_spaces_size);
 
+  char* s0_start, *s0_top, *s0_end;
+  char* s1_start, *s1_top, *s1_end;
+
   for (int pass=1; pass<=2; pass++) {
     if (pass == 1) {
       // The first pass doesn't actually write the data to disk. All it
       // does is to update the fields in the mapinfo->_header.
     } else {

@@ -1267,24 +1268,56 @@
     write_region(mapinfo, MetaspaceShared::mc, &_mc_region, /*read_only=*/false,/*allow_exec=*/true);
     write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false);
     write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false);
     write_region(mapinfo, MetaspaceShared::md, &_md_region, /*read_only=*/false,/*allow_exec=*/false);
     write_region(mapinfo, MetaspaceShared::od, &_od_region, /*read_only=*/true, /*allow_exec=*/false);
-    mapinfo->write_string_regions(_string_regions);
+
+    mapinfo->write_string_regions(_string_regions,
+                                  &s0_start, &s0_top, &s0_end,
+                                  &s1_start, &s1_top, &s1_end);
   }
 
   mapinfo->close();
 
   // Restore the vtable in case we invoke any virtual methods.
   MetaspaceShared::clone_cpp_vtables((intptr_t*)vtbl_list);
 
+  _s0_region.init(s0_start, s0_top, s0_end);
+  _s1_region.init(s1_start, s1_top, s1_end);
+  print_region_stats();
+
   if (log_is_enabled(Info, cds)) {
     ArchiveCompactor::alloc_stats()->print_stats(int(_ro_region.used()), int(_rw_region.used()),
                                                  int(_mc_region.used()), int(_md_region.used()));
   }
 }
 
+void VM_PopulateDumpSharedSpace::print_region_stats() {
+  // Print statistics of all the regions
+  const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() +
+                                _mc_region.reserved() + _md_region.reserved() +
+                                _od_region.reserved() +
+                                _s0_region.reserved() + _s1_region.reserved();
+  const size_t total_bytes = _ro_region.used() + _rw_region.used() +
+                             _mc_region.used() + _md_region.used() +
+                             _od_region.used() +
+                             _s0_region.used() + _s1_region.used();
+  const double total_u_perc = total_bytes / double(total_reserved) * 100.0;
+
+  _mc_region.print(total_reserved);
+  _rw_region.print(total_reserved);
+  _ro_region.print(total_reserved);
+  _md_region.print(total_reserved);
+  _od_region.print(total_reserved);
+  _s0_region.print(total_reserved);
+  _s1_region.print(total_reserved);
+
+  tty->print_cr("total   : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
+                 total_bytes, total_reserved, total_u_perc);
+}
+
+
 // Update a Java object to point its Klass* to the new location after
 // shared archive has been compacted.
 void MetaspaceShared::relocate_klass_ptr(oop o) {
   assert(DumpSharedSpaces, "sanity");
   Klass* k = ArchiveCompactor::get_relocated_klass(o->klass());

@@ -1725,11 +1758,10 @@
   // or so.
   _mc_region.print_out_of_space_msg(name, needed_bytes);
   _rw_region.print_out_of_space_msg(name, needed_bytes);
   _ro_region.print_out_of_space_msg(name, needed_bytes);
   _md_region.print_out_of_space_msg(name, needed_bytes);
-  _st_region.print_out_of_space_msg(name, needed_bytes);
   _od_region.print_out_of_space_msg(name, needed_bytes);
 
   vm_exit_during_initialization(err_msg("Unable to allocate from '%s' region", name),
                                 "Please reduce the number of shared classes.");
 }
< prev index next >