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 "memory/metaspace.hpp"
29 #include "memory/metaspace/chunkManager.hpp"
30 #include "memory/metaspace/commitLimiter.hpp"
31 #include "memory/metaspace/counters.hpp"
32 #include "memory/metaspace/freeChunkList.hpp"
33 #include "memory/metaspace/metaspaceContext.hpp"
34 #include "memory/metaspace/metaspaceCommon.hpp"
35 #include "memory/metaspace/virtualSpaceList.hpp"
36 #include "memory/metaspace/virtualSpaceNode.hpp"
37 #include "runtime/mutexLocker.hpp"
38
39 namespace metaspace {
40
41 #define LOGFMT "VsList @" PTR_FORMAT " (%s)"
42 #define LOGFMT_ARGS p2i(this), this->_name
43
44 // Create a new, empty, expandable list.
VirtualSpaceList(const char * name,CommitLimiter * commit_limiter)45 VirtualSpaceList::VirtualSpaceList(const char* name, CommitLimiter* commit_limiter) :
46 _name(name),
47 _first_node(NULL),
48 _can_expand(true),
49 _commit_limiter(commit_limiter),
50 _reserved_words_counter(),
51 _committed_words_counter()
52 {
53 }
54
55 // Create a new list. The list will contain one node only, which uses the given ReservedSpace.
56 // It will be not expandable beyond that first node.
VirtualSpaceList(const char * name,ReservedSpace rs,CommitLimiter * commit_limiter)57 VirtualSpaceList::VirtualSpaceList(const char* name, ReservedSpace rs, CommitLimiter* commit_limiter) :
58 _name(name),
59 _first_node(NULL),
60 _can_expand(false),
61 _commit_limiter(commit_limiter),
62 _reserved_words_counter(),
63 _committed_words_counter()
64 {
65 // Create the first node spanning the existing ReservedSpace. This will be the only node created
66 // for this list since we cannot expand.
67 VirtualSpaceNode* vsn = VirtualSpaceNode::create_node(rs, _commit_limiter,
68 &_reserved_words_counter, &_committed_words_counter);
69 assert(vsn != NULL, "node creation failed");
70 _first_node = vsn;
71 _first_node->set_next(NULL);
72 _nodes_counter.increment();
73 }
74
~VirtualSpaceList()75 VirtualSpaceList::~VirtualSpaceList() {
76 assert_lock_strong(Metaspace_lock);
77 // Note: normally, there is no reason ever to delete a vslist since they are
78 // global objects, but for gtests it makes sense to allow this.
79 VirtualSpaceNode* vsn = _first_node;
80 VirtualSpaceNode* vsn2 = vsn;
81 while (vsn != NULL) {
82 vsn2 = vsn->next();
83 delete vsn;
84 vsn = vsn2;
85 }
86 }
87
88 // Create a new node and append it to the list. After
89 // this function, _current_node shall point to a new empty node.
90 // List must be expandable for this to work.
create_new_node()91 void VirtualSpaceList::create_new_node() {
92 assert(_can_expand, "List is not expandable");
93 assert_lock_strong(Metaspace_lock);
94
95 VirtualSpaceNode* vsn = VirtualSpaceNode::create_node(Settings::virtual_space_node_default_word_size(),
96 _commit_limiter,
97 &_reserved_words_counter, &_committed_words_counter);
98 vsn->set_next(_first_node);
99 _first_node = vsn;
100 _nodes_counter.increment();
101 }
102
103 // Allocate a root chunk from this list.
104 // Note: this just returns a chunk whose memory is reserved; no memory is committed yet.
105 // Hence, before using this chunk, it must be committed.
106 // Also, no limits are checked, since no committing takes place.
allocate_root_chunk()107 Metachunk* VirtualSpaceList::allocate_root_chunk() {
108 assert_lock_strong(Metaspace_lock);
109
110 if (_first_node == NULL ||
111 _first_node->free_words() < chunklevel::MAX_CHUNK_WORD_SIZE) {
112
113 #ifdef ASSERT
114 // Since all allocations from a VirtualSpaceNode happen in
115 // root-chunk-size units, and the node size must be root-chunk-size aligned,
116 // we should never have left-over space.
117 if (_first_node != NULL) {
118 assert(_first_node->free_words() == 0, "Sanity");
119 }
120 #endif
121
122 if (_can_expand) {
123 create_new_node();
124 UL2(debug, "added new node (now: %d).", num_nodes());
125 } else {
126 UL(debug, "list cannot expand.");
127 return NULL; // We cannot expand this list.
128 }
129 }
130
131 Metachunk* c = _first_node->allocate_root_chunk();
132 assert(c != NULL, "This should have worked");
133
134 return c;
135 }
136
137 // Attempts to purge nodes. This will remove and delete nodes which only contain free chunks.
138 // The free chunks are removed from the freelists before the nodes are deleted.
139 // Return number of purged nodes.
purge(FreeChunkListVector * freelists)140 int VirtualSpaceList::purge(FreeChunkListVector* freelists) {
141 assert_lock_strong(Metaspace_lock);
142 UL(debug, "purging.");
143
144 VirtualSpaceNode* vsn = _first_node;
145 VirtualSpaceNode* prev_vsn = NULL;
146 int num = 0, num_purged = 0;
147 while (vsn != NULL) {
148 VirtualSpaceNode* next_vsn = vsn->next();
149 bool purged = vsn->attempt_purge(freelists);
150 if (purged) {
151 // Note: from now on do not dereference vsn!
152 UL2(debug, "purged node @" PTR_FORMAT ".", p2i(vsn));
153 if (_first_node == vsn) {
154 _first_node = next_vsn;
155 }
156 DEBUG_ONLY(vsn = (VirtualSpaceNode*)((uintptr_t)(0xdeadbeef));)
157 if (prev_vsn != NULL) {
158 prev_vsn->set_next(next_vsn);
159 }
160 num_purged++;
161 _nodes_counter.decrement();
162 } else {
163 prev_vsn = vsn;
164 }
165 vsn = next_vsn;
166 num ++;
167 }
168
169 UL2(debug, "purged %d nodes (before: %d, now: %d)",
170 num_purged, num, num_nodes());
171 return num_purged;
172 }
173
174 // Print all nodes in this space list.
print_on(outputStream * st) const175 void VirtualSpaceList::print_on(outputStream* st) const {
176 MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag);
177
178 st->print_cr("vsl %s:", _name);
179 const VirtualSpaceNode* vsn = _first_node;
180 int n = 0;
181 while (vsn != NULL) {
182 st->print("- node #%d: ", n);
183 vsn->print_on(st);
184 vsn = vsn->next();
185 n++;
186 }
187 st->print_cr("- total %d nodes, " SIZE_FORMAT " reserved words, " SIZE_FORMAT " committed words.",
188 n, reserved_words(), committed_words());
189 }
190
191 #ifdef ASSERT
verify_locked() const192 void VirtualSpaceList::verify_locked() const {
193 assert_lock_strong(Metaspace_lock);
194 assert(_name != NULL, "Sanity");
195
196 int n = 0;
197
198 if (_first_node != NULL) {
199 size_t total_reserved_words = 0;
200 size_t total_committed_words = 0;
201 const VirtualSpaceNode* vsn = _first_node;
202 while (vsn != NULL) {
203 n++;
204 vsn->verify_locked();
205 total_reserved_words += vsn->word_size();
206 total_committed_words += vsn->committed_words();
207 vsn = vsn->next();
208 }
209 _nodes_counter.check(n);
210 _reserved_words_counter.check(total_reserved_words);
211 _committed_words_counter.check(total_committed_words);
212 } else {
213 _reserved_words_counter.check(0);
214 _committed_words_counter.check(0);
215 }
216 }
217
verify() const218 void VirtualSpaceList::verify() const {
219 MutexLocker fcl(Metaspace_lock, Mutex::_no_safepoint_check_flag);
220 verify_locked();
221 }
222 #endif
223
224 // Returns true if this pointer is contained in one of our nodes.
contains(const MetaWord * p) const225 bool VirtualSpaceList::contains(const MetaWord* p) const {
226 const VirtualSpaceNode* vsn = _first_node;
227 while (vsn != NULL) {
228 if (vsn->contains(p)) {
229 return true;
230 }
231 vsn = vsn->next();
232 }
233 return false;
234 }
235
236 // Returns true if the vslist is not expandable and no more root chunks
237 // can be allocated.
is_full() const238 bool VirtualSpaceList::is_full() const {
239 if (!_can_expand && _first_node != NULL && _first_node->free_words() == 0) {
240 return true;
241 }
242 return false;
243 }
244
245 // Convenience methods to return the global class-space chunkmanager
246 // and non-class chunkmanager, respectively.
vslist_class()247 VirtualSpaceList* VirtualSpaceList::vslist_class() {
248 return MetaspaceContext::context_class() == NULL ? NULL : MetaspaceContext::context_class()->vslist();
249 }
250
vslist_nonclass()251 VirtualSpaceList* VirtualSpaceList::vslist_nonclass() {
252 return MetaspaceContext::context_nonclass() == NULL ? NULL : MetaspaceContext::context_nonclass()->vslist();
253 }
254
255 } // namespace metaspace
256