1 /*
2 * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 #include "precompiled.hpp"
25 #include "gc/shared/gcLogPrecious.hpp"
26 #include "gc/z/zAddressSpaceLimit.hpp"
27 #include "gc/z/zGlobals.hpp"
28 #include "gc/z/zVirtualMemory.inline.hpp"
29 #include "services/memTracker.hpp"
30 #include "utilities/debug.hpp"
31 #include "utilities/align.hpp"
32
ZVirtualMemoryManager(size_t max_capacity)33 ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) :
34 _manager(),
35 _initialized(false) {
36
37 // Check max supported heap size
38 if (max_capacity > ZAddressOffsetMax) {
39 log_error_p(gc)("Java heap too large (max supported heap size is " SIZE_FORMAT "G)",
40 ZAddressOffsetMax / G);
41 return;
42 }
43
44 // Reserve address space
45 if (!reserve(max_capacity)) {
46 log_error_pd(gc)("Failed to reserve enough address space for Java heap");
47 return;
48 }
49
50 // Initialize OS specific parts
51 initialize_os();
52
53 // Successfully initialized
54 _initialized = true;
55 }
56
reserve_discontiguous(uintptr_t start,size_t size,size_t min_range)57 size_t ZVirtualMemoryManager::reserve_discontiguous(uintptr_t start, size_t size, size_t min_range) {
58 if (size < min_range) {
59 // Too small
60 return 0;
61 }
62
63 assert(is_aligned(size, ZGranuleSize), "Misaligned");
64
65 if (reserve_contiguous_platform(start, size)) {
66 // Make the address range free
67 _manager.free(start, size);
68 return size;
69 }
70
71 const size_t half = size / 2;
72 if (half < min_range) {
73 // Too small
74 return 0;
75 }
76
77 // Divide and conquer
78 const size_t first_part = align_down(half, ZGranuleSize);
79 const size_t second_part = size - first_part;
80 return reserve_discontiguous(start, first_part, min_range) +
81 reserve_discontiguous(start + first_part, second_part, min_range);
82 }
83
reserve_discontiguous(size_t size)84 size_t ZVirtualMemoryManager::reserve_discontiguous(size_t size) {
85 // Don't try to reserve address ranges smaller than 1% of the requested size.
86 // This avoids an explosion of reservation attempts in case large parts of the
87 // address space is already occupied.
88 const size_t min_range = align_up(size / 100, ZGranuleSize);
89 size_t start = 0;
90 size_t reserved = 0;
91
92 // Reserve size somewhere between [0, ZAddressOffsetMax)
93 while (reserved < size && start < ZAddressOffsetMax) {
94 const size_t remaining = MIN2(size - reserved, ZAddressOffsetMax - start);
95 reserved += reserve_discontiguous(start, remaining, min_range);
96 start += remaining;
97 }
98
99 return reserved;
100 }
101
reserve_contiguous(size_t size)102 bool ZVirtualMemoryManager::reserve_contiguous(size_t size) {
103 // Allow at most 8192 attempts spread evenly across [0, ZAddressOffsetMax)
104 const size_t end = ZAddressOffsetMax - size;
105 const size_t increment = align_up(end / 8192, ZGranuleSize);
106
107 for (size_t start = 0; start <= end; start += increment) {
108 if (reserve_contiguous_platform(start, size)) {
109 // Make the address range free
110 _manager.free(start, size);
111
112 // Success
113 return true;
114 }
115 }
116
117 // Failed
118 return false;
119 }
120
reserve(size_t max_capacity)121 bool ZVirtualMemoryManager::reserve(size_t max_capacity) {
122 const size_t limit = MIN2(ZAddressOffsetMax, ZAddressSpaceLimit::heap_view());
123 const size_t size = MIN2(max_capacity * ZVirtualToPhysicalRatio, limit);
124
125 size_t reserved = size;
126 bool contiguous = true;
127
128 // Prefer a contiguous address space
129 if (!reserve_contiguous(size)) {
130 // Fall back to a discontiguous address space
131 reserved = reserve_discontiguous(size);
132 contiguous = false;
133 }
134
135 log_info_p(gc, init)("Address Space Type: %s/%s/%s",
136 (contiguous ? "Contiguous" : "Discontiguous"),
137 (limit == ZAddressOffsetMax ? "Unrestricted" : "Restricted"),
138 (reserved == size ? "Complete" : "Degraded"));
139 log_info_p(gc, init)("Address Space Size: " SIZE_FORMAT "M x " SIZE_FORMAT " = " SIZE_FORMAT "M",
140 reserved / M, ZHeapViews, (reserved * ZHeapViews) / M);
141
142 return reserved >= max_capacity;
143 }
144
nmt_reserve(uintptr_t start,size_t size)145 void ZVirtualMemoryManager::nmt_reserve(uintptr_t start, size_t size) {
146 MemTracker::record_virtual_memory_reserve((void*)start, size, CALLER_PC);
147 MemTracker::record_virtual_memory_type((void*)start, mtJavaHeap);
148 }
149
is_initialized() const150 bool ZVirtualMemoryManager::is_initialized() const {
151 return _initialized;
152 }
153
alloc(size_t size,bool force_low_address)154 ZVirtualMemory ZVirtualMemoryManager::alloc(size_t size, bool force_low_address) {
155 uintptr_t start;
156
157 // Small pages are allocated at low addresses, while medium/large pages
158 // are allocated at high addresses (unless forced to be at a low address).
159 if (force_low_address || size <= ZPageSizeSmall) {
160 start = _manager.alloc_from_front(size);
161 } else {
162 start = _manager.alloc_from_back(size);
163 }
164
165 return ZVirtualMemory(start, size);
166 }
167
free(const ZVirtualMemory & vmem)168 void ZVirtualMemoryManager::free(const ZVirtualMemory& vmem) {
169 _manager.free(vmem.start(), vmem.size());
170 }
171