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