1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/services/virtualMemoryTracker.cpp Wed Aug 27 08:19:12 2014 -0400 1.3 @@ -0,0 +1,448 @@ 1.4 +/* 1.5 + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 +#include "precompiled.hpp" 1.28 + 1.29 +#include "runtime/threadCritical.hpp" 1.30 +#include "services/virtualMemoryTracker.hpp" 1.31 + 1.32 +size_t VirtualMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(VirtualMemorySnapshot, size_t)]; 1.33 + 1.34 +void VirtualMemorySummary::initialize() { 1.35 + assert(sizeof(_snapshot) >= sizeof(VirtualMemorySnapshot), "Sanity Check"); 1.36 + // Use placement operator new to initialize static data area. 1.37 + ::new ((void*)_snapshot) VirtualMemorySnapshot(); 1.38 +} 1.39 + 1.40 +SortedLinkedList<ReservedMemoryRegion, compare_reserved_region_base> VirtualMemoryTracker::_reserved_regions; 1.41 + 1.42 +int compare_committed_region(const CommittedMemoryRegion& r1, const CommittedMemoryRegion& r2) { 1.43 + return r1.compare(r2); 1.44 +} 1.45 + 1.46 +int compare_reserved_region_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2) { 1.47 + return r1.compare(r2); 1.48 +} 1.49 + 1.50 +bool ReservedMemoryRegion::add_committed_region(address addr, size_t size, const NativeCallStack& stack) { 1.51 + assert(addr != NULL, "Invalid address"); 1.52 + assert(size > 0, "Invalid size"); 1.53 + assert(contain_region(addr, size), "Not contain this region"); 1.54 + 1.55 + if (all_committed()) return true; 1.56 + 1.57 + CommittedMemoryRegion committed_rgn(addr, size, stack); 1.58 + LinkedListNode<CommittedMemoryRegion>* node = _committed_regions.find_node(committed_rgn); 1.59 + if (node != NULL) { 1.60 + CommittedMemoryRegion* rgn = node->data(); 1.61 + if (rgn->same_region(addr, size)) { 1.62 + return true; 1.63 + } 1.64 + 1.65 + if (rgn->adjacent_to(addr, size)) { 1.66 + // check if the next region covers this committed region, 1.67 + // the regions may not be merged due to different call stacks 1.68 + LinkedListNode<CommittedMemoryRegion>* next = 1.69 + node->next(); 1.70 + if (next != NULL && next->data()->contain_region(addr, size)) { 1.71 + if (next->data()->same_region(addr, size)) { 1.72 + next->data()->set_call_stack(stack); 1.73 + } 1.74 + return true; 1.75 + } 1.76 + if (rgn->call_stack()->equals(stack)) { 1.77 + VirtualMemorySummary::record_uncommitted_memory(rgn->size(), flag()); 1.78 + // the two adjacent regions have the same call stack, merge them 1.79 + rgn->expand_region(addr, size); 1.80 + VirtualMemorySummary::record_committed_memory(rgn->size(), flag()); 1.81 + return true; 1.82 + } 1.83 + VirtualMemorySummary::record_committed_memory(size, flag()); 1.84 + if (rgn->base() > addr) { 1.85 + return _committed_regions.insert_before(committed_rgn, node) != NULL; 1.86 + } else { 1.87 + return _committed_regions.insert_after(committed_rgn, node) != NULL; 1.88 + } 1.89 + } 1.90 + assert(rgn->contain_region(addr, size), "Must cover this region"); 1.91 + return true; 1.92 + } else { 1.93 + // New committed region 1.94 + VirtualMemorySummary::record_committed_memory(size, flag()); 1.95 + return add_committed_region(committed_rgn); 1.96 + } 1.97 +} 1.98 + 1.99 +void ReservedMemoryRegion::set_all_committed(bool b) { 1.100 + if (all_committed() != b) { 1.101 + _all_committed = b; 1.102 + if (b) { 1.103 + VirtualMemorySummary::record_committed_memory(size(), flag()); 1.104 + } 1.105 + } 1.106 +} 1.107 + 1.108 +bool ReservedMemoryRegion::remove_uncommitted_region(LinkedListNode<CommittedMemoryRegion>* node, 1.109 + address addr, size_t size) { 1.110 + assert(addr != NULL, "Invalid address"); 1.111 + assert(size > 0, "Invalid size"); 1.112 + 1.113 + CommittedMemoryRegion* rgn = node->data(); 1.114 + assert(rgn->contain_region(addr, size), "Has to be contained"); 1.115 + assert(!rgn->same_region(addr, size), "Can not be the same region"); 1.116 + 1.117 + if (rgn->base() == addr || 1.118 + rgn->end() == addr + size) { 1.119 + rgn->exclude_region(addr, size); 1.120 + return true; 1.121 + } else { 1.122 + // split this region 1.123 + address top =rgn->end(); 1.124 + // use this region for lower part 1.125 + size_t exclude_size = rgn->end() - addr; 1.126 + rgn->exclude_region(addr, exclude_size); 1.127 + 1.128 + // higher part 1.129 + address high_base = addr + size; 1.130 + size_t high_size = top - high_base; 1.131 + 1.132 + CommittedMemoryRegion high_rgn(high_base, high_size, *rgn->call_stack()); 1.133 + LinkedListNode<CommittedMemoryRegion>* high_node = _committed_regions.add(high_rgn); 1.134 + assert(high_node == NULL || node->next() == high_node, "Should be right after"); 1.135 + return (high_node != NULL); 1.136 + } 1.137 + 1.138 + return false; 1.139 +} 1.140 + 1.141 +bool ReservedMemoryRegion::remove_uncommitted_region(address addr, size_t sz) { 1.142 + // uncommit stack guard pages 1.143 + if (flag() == mtThreadStack && !same_region(addr, sz)) { 1.144 + return true; 1.145 + } 1.146 + 1.147 + assert(addr != NULL, "Invalid address"); 1.148 + assert(sz > 0, "Invalid size"); 1.149 + 1.150 + if (all_committed()) { 1.151 + assert(_committed_regions.is_empty(), "Sanity check"); 1.152 + assert(contain_region(addr, sz), "Reserved region does not contain this region"); 1.153 + set_all_committed(false); 1.154 + VirtualMemorySummary::record_uncommitted_memory(sz, flag()); 1.155 + if (same_region(addr, sz)) { 1.156 + return true; 1.157 + } else { 1.158 + CommittedMemoryRegion rgn(base(), size(), *call_stack()); 1.159 + if (rgn.base() == addr || rgn.end() == (addr + sz)) { 1.160 + rgn.exclude_region(addr, sz); 1.161 + return add_committed_region(rgn); 1.162 + } else { 1.163 + // split this region 1.164 + // top of the whole region 1.165 + address top =rgn.end(); 1.166 + // use this region for lower part 1.167 + size_t exclude_size = rgn.end() - addr; 1.168 + rgn.exclude_region(addr, exclude_size); 1.169 + if (add_committed_region(rgn)) { 1.170 + // higher part 1.171 + address high_base = addr + sz; 1.172 + size_t high_size = top - high_base; 1.173 + CommittedMemoryRegion high_rgn(high_base, high_size, emptyStack); 1.174 + return add_committed_region(high_rgn); 1.175 + } else { 1.176 + return false; 1.177 + } 1.178 + } 1.179 + } 1.180 + } else { 1.181 + // we have to walk whole list to remove the committed regions in 1.182 + // specified range 1.183 + LinkedListNode<CommittedMemoryRegion>* head = 1.184 + _committed_regions.head(); 1.185 + LinkedListNode<CommittedMemoryRegion>* prev = NULL; 1.186 + VirtualMemoryRegion uncommitted_rgn(addr, sz); 1.187 + 1.188 + while (head != NULL && !uncommitted_rgn.is_empty()) { 1.189 + CommittedMemoryRegion* crgn = head->data(); 1.190 + // this committed region overlaps to region to uncommit 1.191 + if (crgn->overlap_region(uncommitted_rgn.base(), uncommitted_rgn.size())) { 1.192 + if (crgn->same_region(uncommitted_rgn.base(), uncommitted_rgn.size())) { 1.193 + // find matched region, remove the node will do 1.194 + VirtualMemorySummary::record_uncommitted_memory(uncommitted_rgn.size(), flag()); 1.195 + _committed_regions.remove_after(prev); 1.196 + return true; 1.197 + } else if (crgn->contain_region(uncommitted_rgn.base(), uncommitted_rgn.size())) { 1.198 + // this committed region contains whole uncommitted region 1.199 + VirtualMemorySummary::record_uncommitted_memory(uncommitted_rgn.size(), flag()); 1.200 + return remove_uncommitted_region(head, uncommitted_rgn.base(), uncommitted_rgn.size()); 1.201 + } else if (uncommitted_rgn.contain_region(crgn->base(), crgn->size())) { 1.202 + // this committed region has been uncommitted 1.203 + size_t exclude_size = crgn->end() - uncommitted_rgn.base(); 1.204 + uncommitted_rgn.exclude_region(uncommitted_rgn.base(), exclude_size); 1.205 + VirtualMemorySummary::record_uncommitted_memory(crgn->size(), flag()); 1.206 + LinkedListNode<CommittedMemoryRegion>* tmp = head; 1.207 + head = head->next(); 1.208 + _committed_regions.remove_after(prev); 1.209 + continue; 1.210 + } else if (crgn->contain_address(uncommitted_rgn.base())) { 1.211 + size_t toUncommitted = crgn->end() - uncommitted_rgn.base(); 1.212 + crgn->exclude_region(uncommitted_rgn.base(), toUncommitted); 1.213 + uncommitted_rgn.exclude_region(uncommitted_rgn.base(), toUncommitted); 1.214 + VirtualMemorySummary::record_uncommitted_memory(toUncommitted, flag()); 1.215 + } else if (uncommitted_rgn.contain_address(crgn->base())) { 1.216 + size_t toUncommitted = uncommitted_rgn.end() - crgn->base(); 1.217 + crgn->exclude_region(crgn->base(), toUncommitted); 1.218 + uncommitted_rgn.exclude_region(uncommitted_rgn.end() - toUncommitted, 1.219 + toUncommitted); 1.220 + VirtualMemorySummary::record_uncommitted_memory(toUncommitted, flag()); 1.221 + } 1.222 + } 1.223 + prev = head; 1.224 + head = head->next(); 1.225 + } 1.226 + } 1.227 + 1.228 + return true; 1.229 +} 1.230 + 1.231 +void ReservedMemoryRegion::move_committed_regions(address addr, ReservedMemoryRegion& rgn) { 1.232 + assert(addr != NULL, "Invalid address"); 1.233 + 1.234 + // split committed regions 1.235 + LinkedListNode<CommittedMemoryRegion>* head = 1.236 + _committed_regions.head(); 1.237 + LinkedListNode<CommittedMemoryRegion>* prev = NULL; 1.238 + 1.239 + while (head != NULL) { 1.240 + if (head->data()->base() >= addr) { 1.241 + break; 1.242 + } 1.243 + prev = head; 1.244 + head = head->next(); 1.245 + } 1.246 + 1.247 + if (head != NULL) { 1.248 + if (prev != NULL) { 1.249 + prev->set_next(head->next()); 1.250 + } else { 1.251 + _committed_regions.set_head(NULL); 1.252 + } 1.253 + } 1.254 + 1.255 + rgn._committed_regions.set_head(head); 1.256 +} 1.257 + 1.258 +size_t ReservedMemoryRegion::committed_size() const { 1.259 + if (all_committed()) { 1.260 + return size(); 1.261 + } else { 1.262 + size_t committed = 0; 1.263 + LinkedListNode<CommittedMemoryRegion>* head = 1.264 + _committed_regions.head(); 1.265 + while (head != NULL) { 1.266 + committed += head->data()->size(); 1.267 + head = head->next(); 1.268 + } 1.269 + return committed; 1.270 + } 1.271 +} 1.272 + 1.273 +void ReservedMemoryRegion::set_flag(MEMFLAGS f) { 1.274 + assert((flag() == mtNone || flag() == f), "Overwrite memory type"); 1.275 + if (flag() != f) { 1.276 + VirtualMemorySummary::move_reserved_memory(flag(), f, size()); 1.277 + VirtualMemorySummary::move_committed_memory(flag(), f, committed_size()); 1.278 + _flag = f; 1.279 + } 1.280 +} 1.281 + 1.282 +bool VirtualMemoryTracker::initialize(NMT_TrackingLevel level) { 1.283 + if (level >= NMT_summary) { 1.284 + VirtualMemorySummary::initialize(); 1.285 + } 1.286 + return true; 1.287 +} 1.288 + 1.289 +bool VirtualMemoryTracker::add_reserved_region(address base_addr, size_t size, 1.290 + const NativeCallStack& stack, MEMFLAGS flag, bool all_committed) { 1.291 + assert(base_addr != NULL, "Invalid address"); 1.292 + assert(size > 0, "Invalid size"); 1.293 + 1.294 + ReservedMemoryRegion rgn(base_addr, size, stack, flag); 1.295 + ReservedMemoryRegion* reserved_rgn = _reserved_regions.find(rgn); 1.296 + LinkedListNode<ReservedMemoryRegion>* node; 1.297 + if (reserved_rgn == NULL) { 1.298 + VirtualMemorySummary::record_reserved_memory(size, flag); 1.299 + node = _reserved_regions.add(rgn); 1.300 + if (node != NULL) { 1.301 + node->data()->set_all_committed(all_committed); 1.302 + return true; 1.303 + } else { 1.304 + return false; 1.305 + } 1.306 + } else { 1.307 + if (reserved_rgn->same_region(base_addr, size)) { 1.308 + reserved_rgn->set_call_stack(stack); 1.309 + reserved_rgn->set_flag(flag); 1.310 + return true; 1.311 + } else if (reserved_rgn->adjacent_to(base_addr, size)) { 1.312 + VirtualMemorySummary::record_reserved_memory(size, flag); 1.313 + reserved_rgn->expand_region(base_addr, size); 1.314 + reserved_rgn->set_call_stack(stack); 1.315 + return true; 1.316 + } else { 1.317 + // Overlapped reservation. 1.318 + // It can happen when the regions are thread stacks, as JNI 1.319 + // thread does not detach from VM before exits, and leads to 1.320 + // leak JavaThread object 1.321 + if (reserved_rgn->flag() == mtThreadStack) { 1.322 + guarantee(!CheckJNICalls, "Attached JNI thread exited without being detached"); 1.323 + // Overwrite with new region 1.324 + 1.325 + // Release old region 1.326 + VirtualMemorySummary::record_uncommitted_memory(reserved_rgn->committed_size(), reserved_rgn->flag()); 1.327 + VirtualMemorySummary::record_released_memory(reserved_rgn->size(), reserved_rgn->flag()); 1.328 + 1.329 + // Add new region 1.330 + VirtualMemorySummary::record_reserved_memory(rgn.size(), flag); 1.331 + 1.332 + *reserved_rgn = rgn; 1.333 + return true; 1.334 + } else { 1.335 + ShouldNotReachHere(); 1.336 + return false; 1.337 + } 1.338 + } 1.339 + } 1.340 +} 1.341 + 1.342 +void VirtualMemoryTracker::set_reserved_region_type(address addr, MEMFLAGS flag) { 1.343 + assert(addr != NULL, "Invalid address"); 1.344 + 1.345 + ReservedMemoryRegion rgn(addr, 1); 1.346 + ReservedMemoryRegion* reserved_rgn = _reserved_regions.find(rgn); 1.347 + if (reserved_rgn != NULL) { 1.348 + assert(reserved_rgn->contain_address(addr), "Containment"); 1.349 + if (reserved_rgn->flag() != flag) { 1.350 + assert(reserved_rgn->flag() == mtNone, "Overwrite memory type"); 1.351 + reserved_rgn->set_flag(flag); 1.352 + } 1.353 + } 1.354 +} 1.355 + 1.356 +bool VirtualMemoryTracker::add_committed_region(address addr, size_t size, 1.357 + const NativeCallStack& stack) { 1.358 + assert(addr != NULL, "Invalid address"); 1.359 + assert(size > 0, "Invalid size"); 1.360 + ReservedMemoryRegion rgn(addr, size); 1.361 + ReservedMemoryRegion* reserved_rgn = _reserved_regions.find(rgn); 1.362 + 1.363 + assert(reserved_rgn != NULL, "No reserved region"); 1.364 + assert(reserved_rgn->contain_region(addr, size), "Not completely contained"); 1.365 + return reserved_rgn->add_committed_region(addr, size, stack); 1.366 +} 1.367 + 1.368 +bool VirtualMemoryTracker::remove_uncommitted_region(address addr, size_t size) { 1.369 + assert(addr != NULL, "Invalid address"); 1.370 + assert(size > 0, "Invalid size"); 1.371 + ReservedMemoryRegion rgn(addr, size); 1.372 + ReservedMemoryRegion* reserved_rgn = _reserved_regions.find(rgn); 1.373 + assert(reserved_rgn != NULL, "No reserved region"); 1.374 + assert(reserved_rgn->contain_region(addr, size), "Not completely contained"); 1.375 + return reserved_rgn->remove_uncommitted_region(addr, size); 1.376 +} 1.377 + 1.378 +bool VirtualMemoryTracker::remove_released_region(address addr, size_t size) { 1.379 + assert(addr != NULL, "Invalid address"); 1.380 + assert(size > 0, "Invalid size"); 1.381 + 1.382 + ReservedMemoryRegion rgn(addr, size); 1.383 + ReservedMemoryRegion* reserved_rgn = _reserved_regions.find(rgn); 1.384 + 1.385 + assert(reserved_rgn != NULL, "No reserved region"); 1.386 + 1.387 + // uncommit regions within the released region 1.388 + if (!reserved_rgn->remove_uncommitted_region(addr, size)) { 1.389 + return false; 1.390 + } 1.391 + 1.392 + 1.393 + VirtualMemorySummary::record_released_memory(size, reserved_rgn->flag()); 1.394 + 1.395 + if (reserved_rgn->same_region(addr, size)) { 1.396 + return _reserved_regions.remove(rgn); 1.397 + } else { 1.398 + assert(reserved_rgn->contain_region(addr, size), "Not completely contained"); 1.399 + if (reserved_rgn->base() == addr || 1.400 + reserved_rgn->end() == addr + size) { 1.401 + reserved_rgn->exclude_region(addr, size); 1.402 + return true; 1.403 + } else { 1.404 + address top = reserved_rgn->end(); 1.405 + address high_base = addr + size; 1.406 + ReservedMemoryRegion high_rgn(high_base, top - high_base, 1.407 + *reserved_rgn->call_stack(), reserved_rgn->flag()); 1.408 + 1.409 + // use original region for lower region 1.410 + reserved_rgn->exclude_region(addr, top - addr); 1.411 + LinkedListNode<ReservedMemoryRegion>* new_rgn = _reserved_regions.add(high_rgn); 1.412 + if (new_rgn == NULL) { 1.413 + return false; 1.414 + } else { 1.415 + reserved_rgn->move_committed_regions(addr, *new_rgn->data()); 1.416 + return true; 1.417 + } 1.418 + } 1.419 + } 1.420 +} 1.421 + 1.422 + 1.423 +bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) { 1.424 + ThreadCritical tc; 1.425 + LinkedListNode<ReservedMemoryRegion>* head = _reserved_regions.head(); 1.426 + while (head != NULL) { 1.427 + const ReservedMemoryRegion* rgn = head->peek(); 1.428 + if (!walker->do_allocation_site(rgn)) { 1.429 + return false; 1.430 + } 1.431 + head = head->next(); 1.432 + } 1.433 + return true; 1.434 +} 1.435 + 1.436 +// Transition virtual memory tracking level. 1.437 +bool VirtualMemoryTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) { 1.438 + if (from == NMT_minimal) { 1.439 + assert(to == NMT_summary || to == NMT_detail, "Just check"); 1.440 + VirtualMemorySummary::reset(); 1.441 + } else if (to == NMT_minimal) { 1.442 + assert(from == NMT_summary || from == NMT_detail, "Just check"); 1.443 + // Clean up virtual memory tracking data structures. 1.444 + ThreadCritical tc; 1.445 + _reserved_regions.clear(); 1.446 + } 1.447 + 1.448 + return true; 1.449 +} 1.450 + 1.451 +