g1MemoryPool.hpp revision 1472:c18cbe5936b8
1/* 2 * Copyright (c) 2007, 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 25class G1CollectedHeap; 26 27// This file contains the three classes that represent the memory 28// pools of the G1 spaces: G1EdenPool, G1SurvivorPool, and 29// G1OldGenPool. In G1, unlike our other GCs, we do not have a 30// physical space for each of those spaces. Instead, we allocate 31// regions for all three spaces out of a single pool of regions (that 32// pool basically covers the entire heap). As a result, the eden, 33// survivor, and old gen are considered logical spaces in G1, as each 34// is a set of non-contiguous regions. This is also reflected in the 35// way we map them to memory pools here. The easiest way to have done 36// this would have been to map the entire G1 heap to a single memory 37// pool. However, it's helpful to show how large the eden and survivor 38// get, as this does affect the performance and behavior of G1. Which 39// is why we introduce the three memory pools implemented here. 40// 41// The above approach inroduces a couple of challenging issues in the 42// implementation of the three memory pools: 43// 44// 1) The used space calculation for a pool is not necessarily 45// independent of the others. We can easily get from G1 the overall 46// used space in the entire heap, the number of regions in the young 47// generation (includes both eden and survivors), and the number of 48// survivor regions. So, from that we calculate: 49// 50// survivor_used = survivor_num * region_size 51// eden_used = young_region_num * region_size - survivor_used 52// old_gen_used = overall_used - eden_used - survivor_used 53// 54// Note that survivor_used and eden_used are upper bounds. To get the 55// actual value we would have to iterate over the regions and add up 56// ->used(). But that'd be expensive. So, we'll accept some lack of 57// accuracy for those two. But, we have to be careful when calculating 58// old_gen_used, in case we subtract from overall_used more then the 59// actual number and our result goes negative. 60// 61// 2) Calculating the used space is straightforward, as described 62// above. However, how do we calculate the committed space, given that 63// we allocate space for the eden, survivor, and old gen out of the 64// same pool of regions? One way to do this is to use the used value 65// as also the committed value for the eden and survivor spaces and 66// then calculate the old gen committed space as follows: 67// 68// old_gen_committed = overall_committed - eden_committed - survivor_committed 69// 70// Maybe a better way to do that would be to calculate used for eden 71// and survivor as a sum of ->used() over their regions and then 72// calculate committed as region_num * region_size (i.e., what we use 73// to calculate the used space now). This is something to consider 74// in the future. 75// 76// 3) Another decision that is again not straightforward is what is 77// the max size that each memory pool can grow to. Right now, we set 78// that the committed size for the eden and the survivors and 79// calculate the old gen max as follows (basically, it's a similar 80// pattern to what we use for the committed space, as described 81// above): 82// 83// old_gen_max = overall_max - eden_max - survivor_max 84// 85// 4) Now, there is a very subtle issue with all the above. The 86// framework will call get_memory_usage() on the three pools 87// asynchronously. As a result, each call might get a different value 88// for, say, survivor_num which will yield inconsistent values for 89// eden_used, survivor_used, and old_gen_used (as survivor_num is used 90// in the calculation of all three). This would normally be 91// ok. However, it's possible that this might cause the sum of 92// eden_used, survivor_used, and old_gen_used to go over the max heap 93// size and this seems to sometimes cause JConsole (and maybe other 94// clients) to get confused. There's not a really an easy / clean 95// solution to this problem, due to the asynchrounous nature of the 96// framework. 97 98 99// This class is shared by the three G1 memory pool classes 100// (G1EdenPool, G1SurvivorPool, G1OldGenPool). Given that the way we 101// calculate used / committed bytes for these three pools is related 102// (see comment above), we put the calculations in this class so that 103// we can easily share them among the subclasses. 104class G1MemoryPoolSuper : public CollectedMemoryPool { 105private: 106 // It returns x - y if x > y, 0 otherwise. 107 // As described in the comment above, some of the inputs to the 108 // calculations we have to do are obtained concurrently and hence 109 // may be inconsistent with each other. So, this provides a 110 // defensive way of performing the subtraction and avoids the value 111 // going negative (which would mean a very large result, given that 112 // the parameter are size_t). 113 static size_t subtract_up_to_zero(size_t x, size_t y) { 114 if (x > y) { 115 return x - y; 116 } else { 117 return 0; 118 } 119 } 120 121protected: 122 G1CollectedHeap* _g1h; 123 124 // Would only be called from subclasses. 125 G1MemoryPoolSuper(G1CollectedHeap* g1h, 126 const char* name, 127 size_t init_size, 128 size_t max_size, 129 bool support_usage_threshold); 130 131 // The reason why all the code is in static methods is so that it 132 // can be safely called from the constructors of the subclasses. 133 134 static size_t overall_committed(G1CollectedHeap* g1h) { 135 return g1h->capacity(); 136 } 137 static size_t overall_used(G1CollectedHeap* g1h) { 138 return g1h->used_unlocked(); 139 } 140 static size_t overall_max(G1CollectedHeap* g1h) { 141 return g1h->g1_reserved_obj_bytes(); 142 } 143 144 static size_t eden_space_committed(G1CollectedHeap* g1h); 145 static size_t eden_space_used(G1CollectedHeap* g1h); 146 static size_t eden_space_max(G1CollectedHeap* g1h); 147 148 static size_t survivor_space_committed(G1CollectedHeap* g1h); 149 static size_t survivor_space_used(G1CollectedHeap* g1h); 150 static size_t survivor_space_max(G1CollectedHeap* g1h); 151 152 static size_t old_space_committed(G1CollectedHeap* g1h); 153 static size_t old_space_used(G1CollectedHeap* g1h); 154 static size_t old_space_max(G1CollectedHeap* g1h); 155}; 156 157// Memory pool that represents the G1 eden. 158class G1EdenPool : public G1MemoryPoolSuper { 159public: 160 G1EdenPool(G1CollectedHeap* g1h); 161 162 size_t used_in_bytes() { 163 return eden_space_used(_g1h); 164 } 165 size_t max_size() const { 166 return eden_space_max(_g1h); 167 } 168 MemoryUsage get_memory_usage(); 169}; 170 171// Memory pool that represents the G1 survivor. 172class G1SurvivorPool : public G1MemoryPoolSuper { 173public: 174 G1SurvivorPool(G1CollectedHeap* g1h); 175 176 size_t used_in_bytes() { 177 return survivor_space_used(_g1h); 178 } 179 size_t max_size() const { 180 return survivor_space_max(_g1h); 181 } 182 MemoryUsage get_memory_usage(); 183}; 184 185// Memory pool that represents the G1 old gen. 186class G1OldGenPool : public G1MemoryPoolSuper { 187public: 188 G1OldGenPool(G1CollectedHeap* g1h); 189 190 size_t used_in_bytes() { 191 return old_space_used(_g1h); 192 } 193 size_t max_size() const { 194 return old_space_max(_g1h); 195 } 196 MemoryUsage get_memory_usage(); 197}; 198