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