File: | jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp |
Warning: | line 91, column 22 Value stored to 'orig_level' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. |
3 | * Copyright (c) 2018, 2021 SAP SE. All rights reserved. |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
5 | * |
6 | * This code is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License version 2 only, as |
8 | * published by the Free Software Foundation. |
9 | * |
10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
13 | * version 2 for more details (a copy is included in the LICENSE file that |
14 | * accompanied this code). |
15 | * |
16 | * You should have received a copy of the GNU General Public License version |
17 | * 2 along with this work; if not, write to the Free Software Foundation, |
18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | * |
20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
21 | * or visit www.oracle.com if you need additional information or have any |
22 | * questions. |
23 | * |
24 | */ |
25 | |
26 | #include "precompiled.hpp" |
27 | #include "logging/log.hpp" |
28 | #include "logging/logStream.hpp" |
29 | #include "memory/metaspace/chunkManager.hpp" |
30 | #include "memory/metaspace/internalStats.hpp" |
31 | #include "memory/metaspace/metachunk.hpp" |
32 | #include "memory/metaspace/metaspaceArenaGrowthPolicy.hpp" |
33 | #include "memory/metaspace/metaspaceCommon.hpp" |
34 | #include "memory/metaspace/metaspaceContext.hpp" |
35 | #include "memory/metaspace/metaspaceSettings.hpp" |
36 | #include "memory/metaspace/metaspaceStatistics.hpp" |
37 | #include "memory/metaspace/virtualSpaceList.hpp" |
38 | #include "memory/metaspace/virtualSpaceNode.hpp" |
39 | #include "runtime/mutexLocker.hpp" |
40 | #include "utilities/debug.hpp" |
41 | #include "utilities/globalDefinitions.hpp" |
42 | |
43 | namespace metaspace { |
44 | |
45 | #define LOGFMT"ChkMgr @" "0x%016" "l" "x" " (%s)" "ChkMgr @" PTR_FORMAT"0x%016" "l" "x" " (%s)" |
46 | #define LOGFMT_ARGSp2i(this), this->_name p2i(this), this->_name |
47 | |
48 | // Return a single chunk to the freelist and adjust accounting. No merge is attempted. |
49 | void ChunkManager::return_chunk_simple_locked(Metachunk* c) { |
50 | assert_lock_strong(Metaspace_lock); |
51 | DEBUG_ONLY(c->verify())c->verify(); |
52 | _chunks.add(c); |
53 | c->reset_used_words(); |
54 | // Tracing |
55 | log_debug(metaspace)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChunkManager %s: returned chunk " METACHUNK_FORMAT"@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", |
56 | _name, METACHUNK_FORMAT_ARGS(c)p2i(c), c->get_state_char(), p2i(c->base()), c->level ()); |
57 | } |
58 | |
59 | // Creates a chunk manager with a given name (which is for debug purposes only) |
60 | // and an associated space list which will be used to request new chunks from |
61 | // (see get_chunk()) |
62 | ChunkManager::ChunkManager(const char* name, VirtualSpaceList* space_list) : |
63 | _vslist(space_list), |
64 | _name(name), |
65 | _chunks() |
66 | { |
67 | } |
68 | |
69 | // Given a chunk, split it into a target chunk of a smaller size (higher target level) |
70 | // and at least one, possible several splinter chunks. |
71 | // The original chunk must be outside of the freelist and its state must be free. |
72 | // The splinter chunks are added to the freelist. |
73 | // The resulting target chunk will be located at the same address as the original |
74 | // chunk, but it will of course be smaller (of a higher level). |
75 | // The committed areas within the original chunk carry over to the resulting |
76 | // chunks. |
77 | void ChunkManager::split_chunk_and_add_splinters(Metachunk* c, chunklevel_t target_level) { |
78 | assert_lock_strong(Metaspace_lock); |
79 | assert(c->is_free(), "chunk to be split must be free.")do { if (!(c->is_free())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 79, "assert(" "c->is_free()" ") failed", "chunk to be split must be free." ); ::breakpoint(); } } while (0); |
80 | assert(c->level() < target_level, "Target level must be higher than current level.")do { if (!(c->level() < target_level)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 80, "assert(" "c->level() < target_level" ") failed", "Target level must be higher than current level."); ::breakpoint (); } } while (0); |
81 | assert(c->prev() == NULL && c->next() == NULL, "Chunk must be outside of any list.")do { if (!(c->prev() == __null && c->next() == __null )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 81, "assert(" "c->prev() == __null && c->next() == __null" ") failed", "Chunk must be outside of any list."); ::breakpoint (); } } while (0); |
82 | |
83 | DEBUG_ONLY(chunklevel::check_valid_level(target_level);)chunklevel::check_valid_level(target_level); |
84 | DEBUG_ONLY(c->verify();)c->verify(); |
85 | |
86 | UL2(debug, "splitting chunk " METACHUNK_FORMAT " to " CHKLVL_FORMAT ".",(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "splitting chunk " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " to " "lv%.2d" ".", p2i (this), this->_name, p2i(c), c->get_state_char(), p2i(c ->base()), c->level(), target_level); |
87 | METACHUNK_FORMAT_ARGS(c), target_level)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "splitting chunk " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" " to " "lv%.2d" ".", p2i (this), this->_name, p2i(c), c->get_state_char(), p2i(c ->base()), c->level(), target_level);; |
88 | |
89 | DEBUG_ONLY(size_t committed_words_before = c->committed_words();)size_t committed_words_before = c->committed_words(); |
90 | |
91 | const chunklevel_t orig_level = c->level(); |
Value stored to 'orig_level' during its initialization is never read | |
92 | c->vsnode()->split(target_level, c, &_chunks); |
93 | |
94 | // Splitting should never fail. |
95 | assert(c->level() == target_level, "Sanity")do { if (!(c->level() == target_level)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 95, "assert(" "c->level() == target_level" ") failed", "Sanity" ); ::breakpoint(); } } while (0); |
96 | |
97 | // The size of the committed portion should not change (subject to the reduced chunk size of course) |
98 | #ifdef ASSERT1 |
99 | if (committed_words_before > c->word_size()) { |
100 | assert(c->is_fully_committed(), "Sanity")do { if (!(c->is_fully_committed())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 100, "assert(" "c->is_fully_committed()" ") failed", "Sanity" ); ::breakpoint(); } } while (0); |
101 | } else { |
102 | assert(c->committed_words() == committed_words_before, "Sanity")do { if (!(c->committed_words() == committed_words_before) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 102, "assert(" "c->committed_words() == committed_words_before" ") failed", "Sanity"); ::breakpoint(); } } while (0); |
103 | } |
104 | c->verify(); |
105 | verify_locked(); |
106 | SOMETIMES(c->vsnode()->verify_locked();){ static int counter_ = 0; if (VerifyMetaspaceInterval > 0 ) { counter_++; if (counter_ >= VerifyMetaspaceInterval) { counter_ = 0; { c->vsnode()->verify_locked(); } } } } |
107 | #endif |
108 | InternalStats::inc_num_chunk_splits(); |
109 | } |
110 | |
111 | // On success, returns a chunk of level of <preferred_level>, but at most <max_level>. |
112 | // The first first <min_committed_words> of the chunk are guaranteed to be committed. |
113 | // On error, will return NULL. |
114 | // |
115 | // This function may fail for two reasons: |
116 | // - Either we are unable to reserve space for a new chunk (if the underlying VirtualSpaceList |
117 | // is non-expandable but needs expanding - aka out of compressed class space). |
118 | // - Or, if the necessary space cannot be committed because we hit a commit limit. |
119 | // This may be either the GC threshold or MaxMetaspaceSize. |
120 | Metachunk* ChunkManager::get_chunk(chunklevel_t preferred_level, chunklevel_t max_level, size_t min_committed_words) { |
121 | assert(preferred_level <= max_level, "Sanity")do { if (!(preferred_level <= max_level)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 121, "assert(" "preferred_level <= max_level" ") failed" , "Sanity"); ::breakpoint(); } } while (0); |
122 | assert(chunklevel::level_fitting_word_size(min_committed_words) >= max_level, "Sanity")do { if (!(chunklevel::level_fitting_word_size(min_committed_words ) >= max_level)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 122, "assert(" "chunklevel::level_fitting_word_size(min_committed_words) >= max_level" ") failed", "Sanity"); ::breakpoint(); } } while (0); |
123 | |
124 | MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag); |
125 | |
126 | DEBUG_ONLY(verify_locked();)verify_locked(); |
127 | DEBUG_ONLY(chunklevel::check_valid_level(max_level);)chunklevel::check_valid_level(max_level); |
128 | DEBUG_ONLY(chunklevel::check_valid_level(preferred_level);)chunklevel::check_valid_level(preferred_level); |
129 | |
130 | UL2(debug, "requested chunk: pref_level: " CHKLVL_FORMAT(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "requested chunk: pref_level: " "lv%.2d" ", max_level: " "lv%.2d" ", min committed size: " "%" "l" "u" ".", p2i(this) , this->_name, preferred_level, max_level, min_committed_words ); |
131 | ", max_level: " CHKLVL_FORMAT ", min committed size: " SIZE_FORMAT ".",(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "requested chunk: pref_level: " "lv%.2d" ", max_level: " "lv%.2d" ", min committed size: " "%" "l" "u" ".", p2i(this) , this->_name, preferred_level, max_level, min_committed_words ); |
132 | preferred_level, max_level, min_committed_words)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "requested chunk: pref_level: " "lv%.2d" ", max_level: " "lv%.2d" ", min committed size: " "%" "l" "u" ".", p2i(this) , this->_name, preferred_level, max_level, min_committed_words );; |
133 | |
134 | // First, optimistically look for a chunk which is already committed far enough to hold min_word_size. |
135 | |
136 | // 1) Search best or smaller committed chunks (first attempt): |
137 | // Start at the preferred chunk size and work your way down (level up). |
138 | // But for now, only consider chunks larger than a certain threshold - |
139 | // this is to prevent large loaders (eg boot) from unnecessarily gobbling up |
140 | // all the tiny splinter chunks lambdas leave around. |
141 | Metachunk* c = NULL__null; |
142 | c = _chunks.search_chunk_ascending(preferred_level, MIN2((chunklevel_t)(preferred_level + 2), max_level), min_committed_words); |
143 | |
144 | // 2) Search larger committed chunks: |
145 | // If that did not yield anything, look at larger chunks, which may be committed. We would have to split |
146 | // them first, of course. |
147 | if (c == NULL__null) { |
148 | c = _chunks.search_chunk_descending(preferred_level, min_committed_words); |
149 | } |
150 | // 3) Search best or smaller committed chunks (second attempt): |
151 | // Repeat (1) but now consider even the tiniest chunks as long as they are large enough to hold the |
152 | // committed min size. |
153 | if (c == NULL__null) { |
154 | c = _chunks.search_chunk_ascending(preferred_level, max_level, min_committed_words); |
155 | } |
156 | // if we did not get anything yet, there are no free chunks commmitted enough. Repeat search but look for uncommitted chunks too: |
157 | // 4) Search best or smaller chunks, can be uncommitted: |
158 | if (c == NULL__null) { |
159 | c = _chunks.search_chunk_ascending(preferred_level, max_level, 0); |
160 | } |
161 | // 5) Search a larger uncommitted chunk: |
162 | if (c == NULL__null) { |
163 | c = _chunks.search_chunk_descending(preferred_level, 0); |
164 | } |
165 | |
166 | if (c != NULL__null) { |
167 | UL(trace, "taken from freelist.")(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Trace>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "taken from freelist.", p2i(this), this->_name );; |
168 | } |
169 | |
170 | // Failing all that, allocate a new root chunk from the connected virtual space. |
171 | // This may fail if the underlying vslist cannot be expanded (e.g. compressed class space) |
172 | if (c == NULL__null) { |
173 | c = _vslist->allocate_root_chunk(); |
174 | if (c == NULL__null) { |
175 | UL(info, "failed to get new root chunk.")(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Info))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Info>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "failed to get new root chunk.", p2i(this), this ->_name);; |
176 | } else { |
177 | assert(c->level() == chunklevel::ROOT_CHUNK_LEVEL, "root chunk expected")do { if (!(c->level() == chunklevel::ROOT_CHUNK_LEVEL)) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 177, "assert(" "c->level() == chunklevel::ROOT_CHUNK_LEVEL" ") failed", "root chunk expected"); ::breakpoint(); } } while (0); |
178 | UL(debug, "allocated new root chunk.")(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "allocated new root chunk.", p2i(this), this-> _name);; |
179 | } |
180 | } |
181 | if (c == NULL__null) { |
182 | // If we end up here, we found no match in the freelists and were unable to get a new |
183 | // root chunk (so we used up all address space, e.g. out of CompressedClassSpace). |
184 | UL2(info, "failed to get chunk (preferred level: " CHKLVL_FORMAT(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Info))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Info>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "failed to get chunk (preferred level: " "lv%.2d" ", max level " "lv%.2d" ".", p2i(this), this->_name, preferred_level , max_level); |
185 | ", max level " CHKLVL_FORMAT ".", preferred_level, max_level)(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Info))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Info>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "failed to get chunk (preferred level: " "lv%.2d" ", max level " "lv%.2d" ".", p2i(this), this->_name, preferred_level , max_level);; |
186 | c = NULL__null; |
187 | } |
188 | if (c != NULL__null) { |
189 | // Now we have a chunk. |
190 | // It may be larger than what the caller wanted, so we may want to split it. This should |
191 | // always work. |
192 | if (c->level() < preferred_level) { |
193 | split_chunk_and_add_splinters(c, preferred_level); |
194 | assert(c->level() == preferred_level, "split failed?")do { if (!(c->level() == preferred_level)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 194, "assert(" "c->level() == preferred_level" ") failed" , "split failed?"); ::breakpoint(); } } while (0); |
195 | } |
196 | // Attempt to commit the chunk (depending on settings, we either fully commit it or just |
197 | // commit enough to get the caller going). That may fail if we hit a commit limit. In |
198 | // that case put the chunk back to the freelist (re-merging it with its neighbors if we |
199 | // did split it) and return NULL. |
200 | const size_t to_commit = Settings::new_chunks_are_fully_committed() ? c->word_size() : min_committed_words; |
201 | if (c->committed_words() < to_commit) { |
202 | if (c->ensure_committed_locked(to_commit) == false) { |
203 | UL2(info, "failed to commit " SIZE_FORMAT " words on chunk " METACHUNK_FORMAT ".",(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Info))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Info>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "failed to commit " "%" "l" "u" " words on chunk " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", p2i(this), this->_name, to_commit, p2i(c), c ->get_state_char(), p2i(c->base()), c->level()); |
204 | to_commit, METACHUNK_FORMAT_ARGS(c))(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Info))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Info>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "failed to commit " "%" "l" "u" " words on chunk " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", p2i(this), this->_name, to_commit, p2i(c), c ->get_state_char(), p2i(c->base()), c->level());; |
205 | return_chunk_locked(c); |
206 | c = NULL__null; |
207 | } |
208 | } |
209 | if (c != NULL__null) { |
210 | // Still here? We have now a good chunk, all is well. |
211 | assert(c->committed_words() >= min_committed_words, "Sanity")do { if (!(c->committed_words() >= min_committed_words) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 211, "assert(" "c->committed_words() >= min_committed_words" ") failed", "Sanity"); ::breakpoint(); } } while (0); |
212 | |
213 | // Any chunk returned from ChunkManager shall be marked as in use. |
214 | c->set_in_use(); |
215 | |
216 | UL2(debug, "handing out chunk " METACHUNK_FORMAT ".", METACHUNK_FORMAT_ARGS(c))(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "handing out chunk " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", p2i(this), this-> _name, p2i(c), c->get_state_char(), p2i(c->base()), c-> level());; |
217 | |
218 | InternalStats::inc_num_chunks_taken_from_freelist(); |
219 | |
220 | SOMETIMES(c->vsnode()->verify_locked();){ static int counter_ = 0; if (VerifyMetaspaceInterval > 0 ) { counter_++; if (counter_ >= VerifyMetaspaceInterval) { counter_ = 0; { c->vsnode()->verify_locked(); } } } } |
221 | } |
222 | } |
223 | |
224 | DEBUG_ONLY(verify_locked();)verify_locked(); |
225 | return c; |
226 | } |
227 | |
228 | // Return a single chunk to the ChunkManager and adjust accounting. May merge chunk |
229 | // with neighbors. |
230 | // As a side effect this removes the chunk from whatever list it has been in previously. |
231 | // Happens after a Classloader was unloaded and releases its metaspace chunks. |
232 | // !! Note: this may invalidate the chunk. Do not access the chunk after |
233 | // this function returns !! |
234 | void ChunkManager::return_chunk(Metachunk* c) { |
235 | MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag); |
236 | return_chunk_locked(c); |
237 | } |
238 | |
239 | // See return_chunk(). |
240 | void ChunkManager::return_chunk_locked(Metachunk* c) { |
241 | assert_lock_strong(Metaspace_lock); |
242 | UL2(debug, ": returning chunk " METACHUNK_FORMAT ".", METACHUNK_FORMAT_ARGS(c))(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " ": returning chunk " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", p2i(this), this-> _name, p2i(c), c->get_state_char(), p2i(c->base()), c-> level());; |
243 | DEBUG_ONLY(c->verify();)c->verify(); |
244 | assert(contains_chunk(c) == false, "A chunk to be added to the freelist must not be in the freelist already.")do { if (!(contains_chunk(c) == false)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 244, "assert(" "contains_chunk(c) == false" ") failed", "A chunk to be added to the freelist must not be in the freelist already." ); ::breakpoint(); } } while (0); |
245 | assert(c->is_in_use() || c->is_free(), "Unexpected chunk state")do { if (!(c->is_in_use() || c->is_free())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 245, "assert(" "c->is_in_use() || c->is_free()" ") failed" , "Unexpected chunk state"); ::breakpoint(); } } while (0); |
246 | assert(!c->in_list(), "Remove from list first")do { if (!(!c->in_list())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 246, "assert(" "!c->in_list()" ") failed", "Remove from list first" ); ::breakpoint(); } } while (0); |
247 | |
248 | c->set_free(); |
249 | c->reset_used_words(); |
250 | const chunklevel_t orig_lvl = c->level(); |
251 | |
252 | Metachunk* merged = NULL__null; |
253 | if (!c->is_root_chunk()) { |
254 | // Only attempt merging if we are not of the lowest level already. |
255 | merged = c->vsnode()->merge(c, &_chunks); |
256 | } |
257 | |
258 | if (merged != NULL__null) { |
259 | InternalStats::inc_num_chunk_merges(); |
260 | DEBUG_ONLY(merged->verify())merged->verify(); |
261 | // We did merge chunks and now have a bigger chunk. |
262 | assert(merged->level() < orig_lvl, "Sanity")do { if (!(merged->level() < orig_lvl)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 262, "assert(" "merged->level() < orig_lvl" ") failed" , "Sanity"); ::breakpoint(); } } while (0); |
263 | UL2(debug, "merged into chunk " METACHUNK_FORMAT ".", METACHUNK_FORMAT_ARGS(merged))(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "merged into chunk " "@" "0x%016" "l" "x" ", %c, base " "0x%016" "l" "x" ", level " "lv%.2d" ".", p2i(this), this-> _name, p2i(merged), merged->get_state_char(), p2i(merged-> base()), merged->level());; |
264 | c = merged; |
265 | } |
266 | |
267 | return_chunk_simple_locked(c); |
268 | DEBUG_ONLY(verify_locked();)verify_locked(); |
269 | SOMETIMES(c->vsnode()->verify_locked();){ static int counter_ = 0; if (VerifyMetaspaceInterval > 0 ) { counter_++; if (counter_ >= VerifyMetaspaceInterval) { counter_ = 0; { c->vsnode()->verify_locked(); } } } } |
270 | InternalStats::inc_num_chunks_returned_to_freelist(); |
271 | } |
272 | |
273 | // Given a chunk c, whose state must be "in-use" and must not be a root chunk, attempt to |
274 | // enlarge it in place by claiming its trailing buddy. |
275 | // |
276 | // This will only work if c is the leader of the buddy pair and the trailing buddy is free. |
277 | // |
278 | // If successful, the follower chunk will be removed from the freelists, the leader chunk c will |
279 | // double in size (level decreased by one). |
280 | // |
281 | // On success, true is returned, false otherwise. |
282 | bool ChunkManager::attempt_enlarge_chunk(Metachunk* c) { |
283 | MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag); |
284 | return c->vsnode()->attempt_enlarge_chunk(c, &_chunks); |
285 | } |
286 | |
287 | static void print_word_size_delta(outputStream* st, size_t word_size_1, size_t word_size_2) { |
288 | if (word_size_1 == word_size_2) { |
289 | print_scaled_words(st, word_size_1); |
290 | st->print (" (no change)"); |
291 | } else { |
292 | print_scaled_words(st, word_size_1); |
293 | st->print("->"); |
294 | print_scaled_words(st, word_size_2); |
295 | st->print(" ("); |
296 | if (word_size_2 <= word_size_1) { |
297 | st->print("-"); |
298 | print_scaled_words(st, word_size_1 - word_size_2); |
299 | } else { |
300 | st->print("+"); |
301 | print_scaled_words(st, word_size_2 - word_size_1); |
302 | } |
303 | st->print(")"); |
304 | } |
305 | } |
306 | |
307 | void ChunkManager::purge() { |
308 | MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag); |
309 | UL(info, ": reclaiming memory...")(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Info))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Info>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " ": reclaiming memory...", p2i(this), this->_name );; |
310 | |
311 | const size_t reserved_before = _vslist->reserved_words(); |
312 | const size_t committed_before = _vslist->committed_words(); |
313 | |
314 | // We return unused memory to the Operating System: we iterate over all |
315 | // free chunks and uncommit the backing memory of those large enough to |
316 | // contain one or multiple commit granules (chunks larger than a granule |
317 | // always cover a whole number of granules and start at a granule boundary). |
318 | if (Settings::uncommit_free_chunks()) { |
319 | const chunklevel_t max_level = |
320 | chunklevel::level_fitting_word_size(Settings::commit_granule_words()); |
321 | for (chunklevel_t l = chunklevel::LOWEST_CHUNK_LEVEL; |
322 | l <= max_level; |
323 | l++) { |
324 | // Since we uncommit all chunks at this level, we do not break the "committed chunks are |
325 | // at the front of the list" condition. |
326 | for (Metachunk* c = _chunks.first_at_level(l); c != NULL__null; c = c->next()) { |
327 | c->uncommit_locked(); |
328 | } |
329 | } |
330 | } |
331 | |
332 | const size_t reserved_after = _vslist->reserved_words(); |
333 | const size_t committed_after = _vslist->committed_words(); |
334 | |
335 | // Print a nice report. |
336 | if (reserved_after == reserved_before && committed_after == committed_before) { |
337 | UL(info, "nothing reclaimed.")(!(LogImpl<(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Info))) ? (void)0 : LogImpl <(LogTag::_metaspace), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Info>("ChkMgr @" "0x%016" "l" "x" " (%s)" ": " "nothing reclaimed.", p2i(this), this->_name );; |
338 | } else { |
339 | LogTarget(Info, metaspace)LogTargetImpl<LogLevel::Info, (LogTag::_metaspace), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG)> lt; |
340 | if (lt.is_enabled()) { |
341 | LogStream ls(lt); |
342 | ls.print_cr(LOGFMT"ChkMgr @" "0x%016" "l" "x" " (%s)" ": finished reclaiming memory: ", LOGFMT_ARGSp2i(this), this->_name); |
343 | ls.print("reserved: "); |
344 | print_word_size_delta(&ls, reserved_before, reserved_after); |
345 | ls.cr(); |
346 | ls.print("committed: "); |
347 | print_word_size_delta(&ls, committed_before, committed_after); |
348 | ls.cr(); |
349 | } |
350 | } |
351 | DEBUG_ONLY(_vslist->verify_locked())_vslist->verify_locked(); |
352 | DEBUG_ONLY(verify_locked())verify_locked(); |
353 | } |
354 | |
355 | // Convenience methods to return the global class-space chunkmanager |
356 | // and non-class chunkmanager, respectively. |
357 | ChunkManager* ChunkManager::chunkmanager_class() { |
358 | return MetaspaceContext::context_class() == NULL__null ? NULL__null : MetaspaceContext::context_class()->cm(); |
359 | } |
360 | |
361 | ChunkManager* ChunkManager::chunkmanager_nonclass() { |
362 | return MetaspaceContext::context_nonclass() == NULL__null ? NULL__null : MetaspaceContext::context_nonclass()->cm(); |
363 | } |
364 | |
365 | // Calculates the total number of committed words over all chunks. Walks chunks. |
366 | size_t ChunkManager::calc_committed_word_size() const { |
367 | MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag); |
368 | return calc_committed_word_size_locked(); |
369 | } |
370 | |
371 | size_t ChunkManager::calc_committed_word_size_locked() const { |
372 | assert_lock_strong(Metaspace_lock); |
373 | return _chunks.calc_committed_word_size(); |
374 | } |
375 | |
376 | // Update statistics. |
377 | void ChunkManager::add_to_statistics(ChunkManagerStats* out) const { |
378 | MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag); |
379 | for (chunklevel_t l = chunklevel::ROOT_CHUNK_LEVEL; l <= chunklevel::HIGHEST_CHUNK_LEVEL; l++) { |
380 | out->_num_chunks[l] += _chunks.num_chunks_at_level(l); |
381 | out->_committed_word_size[l] += _chunks.calc_committed_word_size_at_level(l); |
382 | } |
383 | DEBUG_ONLY(out->verify();)out->verify(); |
384 | } |
385 | |
386 | #ifdef ASSERT1 |
387 | |
388 | void ChunkManager::verify() const { |
389 | MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag); |
390 | verify_locked(); |
391 | } |
392 | |
393 | void ChunkManager::verify_locked() const { |
394 | assert_lock_strong(Metaspace_lock); |
395 | assert(_vslist != NULL, "No vslist")do { if (!(_vslist != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/memory/metaspace/chunkManager.cpp" , 395, "assert(" "_vslist != __null" ") failed", "No vslist") ; ::breakpoint(); } } while (0); |
396 | _chunks.verify(); |
397 | } |
398 | |
399 | bool ChunkManager::contains_chunk(Metachunk* c) const { |
400 | return _chunks.contains(c); |
401 | } |
402 | |
403 | #endif // ASSERT |
404 | |
405 | void ChunkManager::print_on(outputStream* st) const { |
406 | MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag); |
407 | print_on_locked(st); |
408 | } |
409 | |
410 | void ChunkManager::print_on_locked(outputStream* st) const { |
411 | assert_lock_strong(Metaspace_lock); |
412 | st->print_cr("cm %s: %d chunks, total word size: " SIZE_FORMAT"%" "l" "u" ".", _name, |
413 | total_num_chunks(), total_word_size()); |
414 | _chunks.print_on(st); |
415 | } |
416 | |
417 | } // namespace metaspace |