annotate src/share/vm/memory/tenuredGeneration.cpp @ 8804:91bf0bdae37b

8008217: CDS: Class data sharing limits the malloc heap on Solaris Summary: In 64bit VM move CDS archive address to 32G on all platforms using new flag SharedBaseAddress. In 32bit VM set CDS archive address to 3Gb on Linux and let other OSs pick the address. Reviewed-by: kvn, dcubed, zgu, hseigel
author coleenp
date Wed, 20 Mar 2013 08:04:54 -0400
parents db9981fd3124
children 8617e38bb4cb
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1 /*
6595
aaf61e68b255 6818524: G1: use ergonomic resizing of PLABs
johnc
parents: 6197
diff changeset
2 * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
0
a61af66fc99e Initial load
duke
parents:
diff changeset
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
a61af66fc99e Initial load
duke
parents:
diff changeset
4 *
a61af66fc99e Initial load
duke
parents:
diff changeset
5 * This code is free software; you can redistribute it and/or modify it
a61af66fc99e Initial load
duke
parents:
diff changeset
6 * under the terms of the GNU General Public License version 2 only, as
a61af66fc99e Initial load
duke
parents:
diff changeset
7 * published by the Free Software Foundation.
a61af66fc99e Initial load
duke
parents:
diff changeset
8 *
a61af66fc99e Initial load
duke
parents:
diff changeset
9 * This code is distributed in the hope that it will be useful, but WITHOUT
a61af66fc99e Initial load
duke
parents:
diff changeset
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
a61af66fc99e Initial load
duke
parents:
diff changeset
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
a61af66fc99e Initial load
duke
parents:
diff changeset
12 * version 2 for more details (a copy is included in the LICENSE file that
a61af66fc99e Initial load
duke
parents:
diff changeset
13 * accompanied this code).
a61af66fc99e Initial load
duke
parents:
diff changeset
14 *
a61af66fc99e Initial load
duke
parents:
diff changeset
15 * You should have received a copy of the GNU General Public License version
a61af66fc99e Initial load
duke
parents:
diff changeset
16 * 2 along with this work; if not, write to the Free Software Foundation,
a61af66fc99e Initial load
duke
parents:
diff changeset
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
a61af66fc99e Initial load
duke
parents:
diff changeset
18 *
1552
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 579
diff changeset
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 579
diff changeset
20 * or visit www.oracle.com if you need additional information or have any
c18cbe5936b8 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 579
diff changeset
21 * questions.
0
a61af66fc99e Initial load
duke
parents:
diff changeset
22 *
a61af66fc99e Initial load
duke
parents:
diff changeset
23 */
a61af66fc99e Initial load
duke
parents:
diff changeset
24
1972
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
25 #include "precompiled.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
26 #include "gc_implementation/shared/collectorCounters.hpp"
6595
aaf61e68b255 6818524: G1: use ergonomic resizing of PLABs
johnc
parents: 6197
diff changeset
27 #include "gc_implementation/shared/parGCAllocBuffer.hpp"
1972
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
28 #include "memory/allocation.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
29 #include "memory/blockOffsetTable.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
30 #include "memory/generation.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
31 #include "memory/generationSpec.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
32 #include "memory/space.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
33 #include "memory/tenuredGeneration.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
34 #include "oops/oop.inline.hpp"
f95d63e2154a 6989984: Use standard include model for Hospot
stefank
parents: 1888
diff changeset
35 #include "runtime/java.hpp"
8001
db9981fd3124 8005915: Unify SERIALGC and INCLUDE_ALTERNATE_GCS
jprovino
parents: 7451
diff changeset
36 #include "utilities/macros.hpp"
0
a61af66fc99e Initial load
duke
parents:
diff changeset
37
a61af66fc99e Initial load
duke
parents:
diff changeset
38 TenuredGeneration::TenuredGeneration(ReservedSpace rs,
a61af66fc99e Initial load
duke
parents:
diff changeset
39 size_t initial_byte_size, int level,
a61af66fc99e Initial load
duke
parents:
diff changeset
40 GenRemSet* remset) :
a61af66fc99e Initial load
duke
parents:
diff changeset
41 OneContigSpaceCardGeneration(rs, initial_byte_size,
a61af66fc99e Initial load
duke
parents:
diff changeset
42 MinHeapDeltaBytes, level, remset, NULL)
a61af66fc99e Initial load
duke
parents:
diff changeset
43 {
a61af66fc99e Initial load
duke
parents:
diff changeset
44 HeapWord* bottom = (HeapWord*) _virtual_space.low();
a61af66fc99e Initial load
duke
parents:
diff changeset
45 HeapWord* end = (HeapWord*) _virtual_space.high();
a61af66fc99e Initial load
duke
parents:
diff changeset
46 _the_space = new TenuredSpace(_bts, MemRegion(bottom, end));
a61af66fc99e Initial load
duke
parents:
diff changeset
47 _the_space->reset_saved_mark();
a61af66fc99e Initial load
duke
parents:
diff changeset
48 _shrink_factor = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
49 _capacity_at_prologue = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
50
a61af66fc99e Initial load
duke
parents:
diff changeset
51 _gc_stats = new GCStats();
a61af66fc99e Initial load
duke
parents:
diff changeset
52
a61af66fc99e Initial load
duke
parents:
diff changeset
53 // initialize performance counters
a61af66fc99e Initial load
duke
parents:
diff changeset
54
a61af66fc99e Initial load
duke
parents:
diff changeset
55 const char* gen_name = "old";
a61af66fc99e Initial load
duke
parents:
diff changeset
56
a61af66fc99e Initial load
duke
parents:
diff changeset
57 // Generation Counters -- generation 1, 1 subspace
a61af66fc99e Initial load
duke
parents:
diff changeset
58 _gen_counters = new GenerationCounters(gen_name, 1, 1, &_virtual_space);
a61af66fc99e Initial load
duke
parents:
diff changeset
59
a61af66fc99e Initial load
duke
parents:
diff changeset
60 _gc_counters = new CollectorCounters("MSC", 1);
a61af66fc99e Initial load
duke
parents:
diff changeset
61
a61af66fc99e Initial load
duke
parents:
diff changeset
62 _space_counters = new CSpaceCounters(gen_name, 0,
a61af66fc99e Initial load
duke
parents:
diff changeset
63 _virtual_space.reserved_size(),
a61af66fc99e Initial load
duke
parents:
diff changeset
64 _the_space, _gen_counters);
8001
db9981fd3124 8005915: Unify SERIALGC and INCLUDE_ALTERNATE_GCS
jprovino
parents: 7451
diff changeset
65 #if INCLUDE_ALL_GCS
7451
ca0a78017dc7 8005396: Use ParNew with only one thread instead of DefNew as default for CMS on single CPU machines
brutisso
parents: 6595
diff changeset
66 if (UseParNewGC) {
0
a61af66fc99e Initial load
duke
parents:
diff changeset
67 typedef ParGCAllocBufferWithBOT* ParGCAllocBufferWithBOTPtr;
a61af66fc99e Initial load
duke
parents:
diff changeset
68 _alloc_buffers = NEW_C_HEAP_ARRAY(ParGCAllocBufferWithBOTPtr,
6197
d2a62e0f25eb 6995781: Native Memory Tracking (Phase 1)
zgu
parents: 1972
diff changeset
69 ParallelGCThreads, mtGC);
0
a61af66fc99e Initial load
duke
parents:
diff changeset
70 if (_alloc_buffers == NULL)
a61af66fc99e Initial load
duke
parents:
diff changeset
71 vm_exit_during_initialization("Could not allocate alloc_buffers");
a61af66fc99e Initial load
duke
parents:
diff changeset
72 for (uint i = 0; i < ParallelGCThreads; i++) {
a61af66fc99e Initial load
duke
parents:
diff changeset
73 _alloc_buffers[i] =
a61af66fc99e Initial load
duke
parents:
diff changeset
74 new ParGCAllocBufferWithBOT(OldPLABSize, _bts);
a61af66fc99e Initial load
duke
parents:
diff changeset
75 if (_alloc_buffers[i] == NULL)
a61af66fc99e Initial load
duke
parents:
diff changeset
76 vm_exit_during_initialization("Could not allocate alloc_buffers");
a61af66fc99e Initial load
duke
parents:
diff changeset
77 }
a61af66fc99e Initial load
duke
parents:
diff changeset
78 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
79 _alloc_buffers = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
80 }
8001
db9981fd3124 8005915: Unify SERIALGC and INCLUDE_ALTERNATE_GCS
jprovino
parents: 7451
diff changeset
81 #endif // INCLUDE_ALL_GCS
0
a61af66fc99e Initial load
duke
parents:
diff changeset
82 }
a61af66fc99e Initial load
duke
parents:
diff changeset
83
a61af66fc99e Initial load
duke
parents:
diff changeset
84
a61af66fc99e Initial load
duke
parents:
diff changeset
85 const char* TenuredGeneration::name() const {
a61af66fc99e Initial load
duke
parents:
diff changeset
86 return "tenured generation";
a61af66fc99e Initial load
duke
parents:
diff changeset
87 }
a61af66fc99e Initial load
duke
parents:
diff changeset
88
a61af66fc99e Initial load
duke
parents:
diff changeset
89 void TenuredGeneration::compute_new_size() {
a61af66fc99e Initial load
duke
parents:
diff changeset
90 assert(_shrink_factor <= 100, "invalid shrink factor");
a61af66fc99e Initial load
duke
parents:
diff changeset
91 size_t current_shrink_factor = _shrink_factor;
a61af66fc99e Initial load
duke
parents:
diff changeset
92 _shrink_factor = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
93
a61af66fc99e Initial load
duke
parents:
diff changeset
94 // We don't have floating point command-line arguments
a61af66fc99e Initial load
duke
parents:
diff changeset
95 // Note: argument processing ensures that MinHeapFreeRatio < 100.
a61af66fc99e Initial load
duke
parents:
diff changeset
96 const double minimum_free_percentage = MinHeapFreeRatio / 100.0;
a61af66fc99e Initial load
duke
parents:
diff changeset
97 const double maximum_used_percentage = 1.0 - minimum_free_percentage;
a61af66fc99e Initial load
duke
parents:
diff changeset
98
a61af66fc99e Initial load
duke
parents:
diff changeset
99 // Compute some numbers about the state of the heap.
a61af66fc99e Initial load
duke
parents:
diff changeset
100 const size_t used_after_gc = used();
a61af66fc99e Initial load
duke
parents:
diff changeset
101 const size_t capacity_after_gc = capacity();
a61af66fc99e Initial load
duke
parents:
diff changeset
102
a61af66fc99e Initial load
duke
parents:
diff changeset
103 const double min_tmp = used_after_gc / maximum_used_percentage;
a61af66fc99e Initial load
duke
parents:
diff changeset
104 size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx));
a61af66fc99e Initial load
duke
parents:
diff changeset
105 // Don't shrink less than the initial generation size
a61af66fc99e Initial load
duke
parents:
diff changeset
106 minimum_desired_capacity = MAX2(minimum_desired_capacity,
a61af66fc99e Initial load
duke
parents:
diff changeset
107 spec()->init_size());
a61af66fc99e Initial load
duke
parents:
diff changeset
108 assert(used_after_gc <= minimum_desired_capacity, "sanity check");
a61af66fc99e Initial load
duke
parents:
diff changeset
109
a61af66fc99e Initial load
duke
parents:
diff changeset
110 if (PrintGC && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
111 const size_t free_after_gc = free();
a61af66fc99e Initial load
duke
parents:
diff changeset
112 const double free_percentage = ((double)free_after_gc) / capacity_after_gc;
a61af66fc99e Initial load
duke
parents:
diff changeset
113 gclog_or_tty->print_cr("TenuredGeneration::compute_new_size: ");
a61af66fc99e Initial load
duke
parents:
diff changeset
114 gclog_or_tty->print_cr(" "
a61af66fc99e Initial load
duke
parents:
diff changeset
115 " minimum_free_percentage: %6.2f"
a61af66fc99e Initial load
duke
parents:
diff changeset
116 " maximum_used_percentage: %6.2f",
a61af66fc99e Initial load
duke
parents:
diff changeset
117 minimum_free_percentage,
a61af66fc99e Initial load
duke
parents:
diff changeset
118 maximum_used_percentage);
a61af66fc99e Initial load
duke
parents:
diff changeset
119 gclog_or_tty->print_cr(" "
a61af66fc99e Initial load
duke
parents:
diff changeset
120 " free_after_gc : %6.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
121 " used_after_gc : %6.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
122 " capacity_after_gc : %6.1fK",
a61af66fc99e Initial load
duke
parents:
diff changeset
123 free_after_gc / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
124 used_after_gc / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
125 capacity_after_gc / (double) K);
a61af66fc99e Initial load
duke
parents:
diff changeset
126 gclog_or_tty->print_cr(" "
a61af66fc99e Initial load
duke
parents:
diff changeset
127 " free_percentage: %6.2f",
a61af66fc99e Initial load
duke
parents:
diff changeset
128 free_percentage);
a61af66fc99e Initial load
duke
parents:
diff changeset
129 }
a61af66fc99e Initial load
duke
parents:
diff changeset
130
a61af66fc99e Initial load
duke
parents:
diff changeset
131 if (capacity_after_gc < minimum_desired_capacity) {
a61af66fc99e Initial load
duke
parents:
diff changeset
132 // If we have less free space than we want then expand
a61af66fc99e Initial load
duke
parents:
diff changeset
133 size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
a61af66fc99e Initial load
duke
parents:
diff changeset
134 // Don't expand unless it's significant
a61af66fc99e Initial load
duke
parents:
diff changeset
135 if (expand_bytes >= _min_heap_delta_bytes) {
a61af66fc99e Initial load
duke
parents:
diff changeset
136 expand(expand_bytes, 0); // safe if expansion fails
a61af66fc99e Initial load
duke
parents:
diff changeset
137 }
a61af66fc99e Initial load
duke
parents:
diff changeset
138 if (PrintGC && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
139 gclog_or_tty->print_cr(" expanding:"
a61af66fc99e Initial load
duke
parents:
diff changeset
140 " minimum_desired_capacity: %6.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
141 " expand_bytes: %6.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
142 " _min_heap_delta_bytes: %6.1fK",
a61af66fc99e Initial load
duke
parents:
diff changeset
143 minimum_desired_capacity / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
144 expand_bytes / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
145 _min_heap_delta_bytes / (double) K);
a61af66fc99e Initial load
duke
parents:
diff changeset
146 }
a61af66fc99e Initial load
duke
parents:
diff changeset
147 return;
a61af66fc99e Initial load
duke
parents:
diff changeset
148 }
a61af66fc99e Initial load
duke
parents:
diff changeset
149
a61af66fc99e Initial load
duke
parents:
diff changeset
150 // No expansion, now see if we want to shrink
a61af66fc99e Initial load
duke
parents:
diff changeset
151 size_t shrink_bytes = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
152 // We would never want to shrink more than this
a61af66fc99e Initial load
duke
parents:
diff changeset
153 size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity;
a61af66fc99e Initial load
duke
parents:
diff changeset
154
a61af66fc99e Initial load
duke
parents:
diff changeset
155 if (MaxHeapFreeRatio < 100) {
a61af66fc99e Initial load
duke
parents:
diff changeset
156 const double maximum_free_percentage = MaxHeapFreeRatio / 100.0;
a61af66fc99e Initial load
duke
parents:
diff changeset
157 const double minimum_used_percentage = 1.0 - maximum_free_percentage;
a61af66fc99e Initial load
duke
parents:
diff changeset
158 const double max_tmp = used_after_gc / minimum_used_percentage;
a61af66fc99e Initial load
duke
parents:
diff changeset
159 size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx));
a61af66fc99e Initial load
duke
parents:
diff changeset
160 maximum_desired_capacity = MAX2(maximum_desired_capacity,
a61af66fc99e Initial load
duke
parents:
diff changeset
161 spec()->init_size());
a61af66fc99e Initial load
duke
parents:
diff changeset
162 if (PrintGC && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
163 gclog_or_tty->print_cr(" "
a61af66fc99e Initial load
duke
parents:
diff changeset
164 " maximum_free_percentage: %6.2f"
a61af66fc99e Initial load
duke
parents:
diff changeset
165 " minimum_used_percentage: %6.2f",
a61af66fc99e Initial load
duke
parents:
diff changeset
166 maximum_free_percentage,
a61af66fc99e Initial load
duke
parents:
diff changeset
167 minimum_used_percentage);
a61af66fc99e Initial load
duke
parents:
diff changeset
168 gclog_or_tty->print_cr(" "
a61af66fc99e Initial load
duke
parents:
diff changeset
169 " _capacity_at_prologue: %6.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
170 " minimum_desired_capacity: %6.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
171 " maximum_desired_capacity: %6.1fK",
a61af66fc99e Initial load
duke
parents:
diff changeset
172 _capacity_at_prologue / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
173 minimum_desired_capacity / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
174 maximum_desired_capacity / (double) K);
a61af66fc99e Initial load
duke
parents:
diff changeset
175 }
a61af66fc99e Initial load
duke
parents:
diff changeset
176 assert(minimum_desired_capacity <= maximum_desired_capacity,
a61af66fc99e Initial load
duke
parents:
diff changeset
177 "sanity check");
a61af66fc99e Initial load
duke
parents:
diff changeset
178
a61af66fc99e Initial load
duke
parents:
diff changeset
179 if (capacity_after_gc > maximum_desired_capacity) {
a61af66fc99e Initial load
duke
parents:
diff changeset
180 // Capacity too large, compute shrinking size
a61af66fc99e Initial load
duke
parents:
diff changeset
181 shrink_bytes = capacity_after_gc - maximum_desired_capacity;
a61af66fc99e Initial load
duke
parents:
diff changeset
182 // We don't want shrink all the way back to initSize if people call
a61af66fc99e Initial load
duke
parents:
diff changeset
183 // System.gc(), because some programs do that between "phases" and then
a61af66fc99e Initial load
duke
parents:
diff changeset
184 // we'd just have to grow the heap up again for the next phase. So we
a61af66fc99e Initial load
duke
parents:
diff changeset
185 // damp the shrinking: 0% on the first call, 10% on the second call, 40%
a61af66fc99e Initial load
duke
parents:
diff changeset
186 // on the third call, and 100% by the fourth call. But if we recompute
a61af66fc99e Initial load
duke
parents:
diff changeset
187 // size without shrinking, it goes back to 0%.
a61af66fc99e Initial load
duke
parents:
diff changeset
188 shrink_bytes = shrink_bytes / 100 * current_shrink_factor;
a61af66fc99e Initial load
duke
parents:
diff changeset
189 assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size");
a61af66fc99e Initial load
duke
parents:
diff changeset
190 if (current_shrink_factor == 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
191 _shrink_factor = 10;
a61af66fc99e Initial load
duke
parents:
diff changeset
192 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
193 _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100);
a61af66fc99e Initial load
duke
parents:
diff changeset
194 }
a61af66fc99e Initial load
duke
parents:
diff changeset
195 if (PrintGC && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
196 gclog_or_tty->print_cr(" "
a61af66fc99e Initial load
duke
parents:
diff changeset
197 " shrinking:"
a61af66fc99e Initial load
duke
parents:
diff changeset
198 " initSize: %.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
199 " maximum_desired_capacity: %.1fK",
a61af66fc99e Initial load
duke
parents:
diff changeset
200 spec()->init_size() / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
201 maximum_desired_capacity / (double) K);
a61af66fc99e Initial load
duke
parents:
diff changeset
202 gclog_or_tty->print_cr(" "
a61af66fc99e Initial load
duke
parents:
diff changeset
203 " shrink_bytes: %.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
204 " current_shrink_factor: %d"
a61af66fc99e Initial load
duke
parents:
diff changeset
205 " new shrink factor: %d"
a61af66fc99e Initial load
duke
parents:
diff changeset
206 " _min_heap_delta_bytes: %.1fK",
a61af66fc99e Initial load
duke
parents:
diff changeset
207 shrink_bytes / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
208 current_shrink_factor,
a61af66fc99e Initial load
duke
parents:
diff changeset
209 _shrink_factor,
a61af66fc99e Initial load
duke
parents:
diff changeset
210 _min_heap_delta_bytes / (double) K);
a61af66fc99e Initial load
duke
parents:
diff changeset
211 }
a61af66fc99e Initial load
duke
parents:
diff changeset
212 }
a61af66fc99e Initial load
duke
parents:
diff changeset
213 }
a61af66fc99e Initial load
duke
parents:
diff changeset
214
a61af66fc99e Initial load
duke
parents:
diff changeset
215 if (capacity_after_gc > _capacity_at_prologue) {
a61af66fc99e Initial load
duke
parents:
diff changeset
216 // We might have expanded for promotions, in which case we might want to
a61af66fc99e Initial load
duke
parents:
diff changeset
217 // take back that expansion if there's room after GC. That keeps us from
a61af66fc99e Initial load
duke
parents:
diff changeset
218 // stretching the heap with promotions when there's plenty of room.
a61af66fc99e Initial load
duke
parents:
diff changeset
219 size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue;
a61af66fc99e Initial load
duke
parents:
diff changeset
220 expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes);
a61af66fc99e Initial load
duke
parents:
diff changeset
221 // We have two shrinking computations, take the largest
a61af66fc99e Initial load
duke
parents:
diff changeset
222 shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion);
a61af66fc99e Initial load
duke
parents:
diff changeset
223 assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size");
a61af66fc99e Initial load
duke
parents:
diff changeset
224 if (PrintGC && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
225 gclog_or_tty->print_cr(" "
a61af66fc99e Initial load
duke
parents:
diff changeset
226 " aggressive shrinking:"
a61af66fc99e Initial load
duke
parents:
diff changeset
227 " _capacity_at_prologue: %.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
228 " capacity_after_gc: %.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
229 " expansion_for_promotion: %.1fK"
a61af66fc99e Initial load
duke
parents:
diff changeset
230 " shrink_bytes: %.1fK",
a61af66fc99e Initial load
duke
parents:
diff changeset
231 capacity_after_gc / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
232 _capacity_at_prologue / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
233 expansion_for_promotion / (double) K,
a61af66fc99e Initial load
duke
parents:
diff changeset
234 shrink_bytes / (double) K);
a61af66fc99e Initial load
duke
parents:
diff changeset
235 }
a61af66fc99e Initial load
duke
parents:
diff changeset
236 }
a61af66fc99e Initial load
duke
parents:
diff changeset
237 // Don't shrink unless it's significant
a61af66fc99e Initial load
duke
parents:
diff changeset
238 if (shrink_bytes >= _min_heap_delta_bytes) {
a61af66fc99e Initial load
duke
parents:
diff changeset
239 shrink(shrink_bytes);
a61af66fc99e Initial load
duke
parents:
diff changeset
240 }
a61af66fc99e Initial load
duke
parents:
diff changeset
241 assert(used() == used_after_gc && used_after_gc <= capacity(),
a61af66fc99e Initial load
duke
parents:
diff changeset
242 "sanity check");
a61af66fc99e Initial load
duke
parents:
diff changeset
243 }
a61af66fc99e Initial load
duke
parents:
diff changeset
244
a61af66fc99e Initial load
duke
parents:
diff changeset
245 void TenuredGeneration::gc_prologue(bool full) {
a61af66fc99e Initial load
duke
parents:
diff changeset
246 _capacity_at_prologue = capacity();
a61af66fc99e Initial load
duke
parents:
diff changeset
247 _used_at_prologue = used();
a61af66fc99e Initial load
duke
parents:
diff changeset
248 if (VerifyBeforeGC) {
a61af66fc99e Initial load
duke
parents:
diff changeset
249 verify_alloc_buffers_clean();
a61af66fc99e Initial load
duke
parents:
diff changeset
250 }
a61af66fc99e Initial load
duke
parents:
diff changeset
251 }
a61af66fc99e Initial load
duke
parents:
diff changeset
252
a61af66fc99e Initial load
duke
parents:
diff changeset
253 void TenuredGeneration::gc_epilogue(bool full) {
a61af66fc99e Initial load
duke
parents:
diff changeset
254 if (VerifyAfterGC) {
a61af66fc99e Initial load
duke
parents:
diff changeset
255 verify_alloc_buffers_clean();
a61af66fc99e Initial load
duke
parents:
diff changeset
256 }
a61af66fc99e Initial load
duke
parents:
diff changeset
257 OneContigSpaceCardGeneration::gc_epilogue(full);
a61af66fc99e Initial load
duke
parents:
diff changeset
258 }
a61af66fc99e Initial load
duke
parents:
diff changeset
259
a61af66fc99e Initial load
duke
parents:
diff changeset
260
a61af66fc99e Initial load
duke
parents:
diff changeset
261 bool TenuredGeneration::should_collect(bool full,
a61af66fc99e Initial load
duke
parents:
diff changeset
262 size_t size,
a61af66fc99e Initial load
duke
parents:
diff changeset
263 bool is_tlab) {
a61af66fc99e Initial load
duke
parents:
diff changeset
264 // This should be one big conditional or (||), but I want to be able to tell
a61af66fc99e Initial load
duke
parents:
diff changeset
265 // why it returns what it returns (without re-evaluating the conditionals
a61af66fc99e Initial load
duke
parents:
diff changeset
266 // in case they aren't idempotent), so I'm doing it this way.
a61af66fc99e Initial load
duke
parents:
diff changeset
267 // DeMorgan says it's okay.
a61af66fc99e Initial load
duke
parents:
diff changeset
268 bool result = false;
a61af66fc99e Initial load
duke
parents:
diff changeset
269 if (!result && full) {
a61af66fc99e Initial load
duke
parents:
diff changeset
270 result = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
271 if (PrintGC && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
272 gclog_or_tty->print_cr("TenuredGeneration::should_collect: because"
a61af66fc99e Initial load
duke
parents:
diff changeset
273 " full");
a61af66fc99e Initial load
duke
parents:
diff changeset
274 }
a61af66fc99e Initial load
duke
parents:
diff changeset
275 }
a61af66fc99e Initial load
duke
parents:
diff changeset
276 if (!result && should_allocate(size, is_tlab)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
277 result = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
278 if (PrintGC && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
279 gclog_or_tty->print_cr("TenuredGeneration::should_collect: because"
a61af66fc99e Initial load
duke
parents:
diff changeset
280 " should_allocate(" SIZE_FORMAT ")",
a61af66fc99e Initial load
duke
parents:
diff changeset
281 size);
a61af66fc99e Initial load
duke
parents:
diff changeset
282 }
a61af66fc99e Initial load
duke
parents:
diff changeset
283 }
a61af66fc99e Initial load
duke
parents:
diff changeset
284 // If we don't have very much free space.
a61af66fc99e Initial load
duke
parents:
diff changeset
285 // XXX: 10000 should be a percentage of the capacity!!!
a61af66fc99e Initial load
duke
parents:
diff changeset
286 if (!result && free() < 10000) {
a61af66fc99e Initial load
duke
parents:
diff changeset
287 result = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
288 if (PrintGC && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
289 gclog_or_tty->print_cr("TenuredGeneration::should_collect: because"
a61af66fc99e Initial load
duke
parents:
diff changeset
290 " free(): " SIZE_FORMAT,
a61af66fc99e Initial load
duke
parents:
diff changeset
291 free());
a61af66fc99e Initial load
duke
parents:
diff changeset
292 }
a61af66fc99e Initial load
duke
parents:
diff changeset
293 }
a61af66fc99e Initial load
duke
parents:
diff changeset
294 // If we had to expand to accomodate promotions from younger generations
a61af66fc99e Initial load
duke
parents:
diff changeset
295 if (!result && _capacity_at_prologue < capacity()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
296 result = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
297 if (PrintGC && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
298 gclog_or_tty->print_cr("TenuredGeneration::should_collect: because"
a61af66fc99e Initial load
duke
parents:
diff changeset
299 "_capacity_at_prologue: " SIZE_FORMAT " < capacity(): " SIZE_FORMAT,
a61af66fc99e Initial load
duke
parents:
diff changeset
300 _capacity_at_prologue, capacity());
a61af66fc99e Initial load
duke
parents:
diff changeset
301 }
a61af66fc99e Initial load
duke
parents:
diff changeset
302 }
a61af66fc99e Initial load
duke
parents:
diff changeset
303 return result;
a61af66fc99e Initial load
duke
parents:
diff changeset
304 }
a61af66fc99e Initial load
duke
parents:
diff changeset
305
a61af66fc99e Initial load
duke
parents:
diff changeset
306 void TenuredGeneration::collect(bool full,
a61af66fc99e Initial load
duke
parents:
diff changeset
307 bool clear_all_soft_refs,
a61af66fc99e Initial load
duke
parents:
diff changeset
308 size_t size,
a61af66fc99e Initial load
duke
parents:
diff changeset
309 bool is_tlab) {
a61af66fc99e Initial load
duke
parents:
diff changeset
310 retire_alloc_buffers_before_full_gc();
a61af66fc99e Initial load
duke
parents:
diff changeset
311 OneContigSpaceCardGeneration::collect(full, clear_all_soft_refs,
a61af66fc99e Initial load
duke
parents:
diff changeset
312 size, is_tlab);
a61af66fc99e Initial load
duke
parents:
diff changeset
313 }
a61af66fc99e Initial load
duke
parents:
diff changeset
314
a61af66fc99e Initial load
duke
parents:
diff changeset
315 void TenuredGeneration::update_gc_stats(int current_level,
a61af66fc99e Initial load
duke
parents:
diff changeset
316 bool full) {
a61af66fc99e Initial load
duke
parents:
diff changeset
317 // If the next lower level(s) has been collected, gather any statistics
a61af66fc99e Initial load
duke
parents:
diff changeset
318 // that are of interest at this point.
a61af66fc99e Initial load
duke
parents:
diff changeset
319 if (!full && (current_level + 1) == level()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
320 // Calculate size of data promoted from the younger generations
a61af66fc99e Initial load
duke
parents:
diff changeset
321 // before doing the collection.
a61af66fc99e Initial load
duke
parents:
diff changeset
322 size_t used_before_gc = used();
a61af66fc99e Initial load
duke
parents:
diff changeset
323
a61af66fc99e Initial load
duke
parents:
diff changeset
324 // If the younger gen collections were skipped, then the
a61af66fc99e Initial load
duke
parents:
diff changeset
325 // number of promoted bytes will be 0 and adding it to the
a61af66fc99e Initial load
duke
parents:
diff changeset
326 // average will incorrectly lessen the average. It is, however,
a61af66fc99e Initial load
duke
parents:
diff changeset
327 // also possible that no promotion was needed.
a61af66fc99e Initial load
duke
parents:
diff changeset
328 if (used_before_gc >= _used_at_prologue) {
a61af66fc99e Initial load
duke
parents:
diff changeset
329 size_t promoted_in_bytes = used_before_gc - _used_at_prologue;
a61af66fc99e Initial load
duke
parents:
diff changeset
330 gc_stats()->avg_promoted()->sample(promoted_in_bytes);
a61af66fc99e Initial load
duke
parents:
diff changeset
331 }
a61af66fc99e Initial load
duke
parents:
diff changeset
332 }
a61af66fc99e Initial load
duke
parents:
diff changeset
333 }
a61af66fc99e Initial load
duke
parents:
diff changeset
334
a61af66fc99e Initial load
duke
parents:
diff changeset
335 void TenuredGeneration::update_counters() {
a61af66fc99e Initial load
duke
parents:
diff changeset
336 if (UsePerfData) {
a61af66fc99e Initial load
duke
parents:
diff changeset
337 _space_counters->update_all();
a61af66fc99e Initial load
duke
parents:
diff changeset
338 _gen_counters->update_all();
a61af66fc99e Initial load
duke
parents:
diff changeset
339 }
a61af66fc99e Initial load
duke
parents:
diff changeset
340 }
a61af66fc99e Initial load
duke
parents:
diff changeset
341
a61af66fc99e Initial load
duke
parents:
diff changeset
342
8001
db9981fd3124 8005915: Unify SERIALGC and INCLUDE_ALTERNATE_GCS
jprovino
parents: 7451
diff changeset
343 #if INCLUDE_ALL_GCS
0
a61af66fc99e Initial load
duke
parents:
diff changeset
344 oop TenuredGeneration::par_promote(int thread_num,
a61af66fc99e Initial load
duke
parents:
diff changeset
345 oop old, markOop m, size_t word_sz) {
a61af66fc99e Initial load
duke
parents:
diff changeset
346
a61af66fc99e Initial load
duke
parents:
diff changeset
347 ParGCAllocBufferWithBOT* buf = _alloc_buffers[thread_num];
a61af66fc99e Initial load
duke
parents:
diff changeset
348 HeapWord* obj_ptr = buf->allocate(word_sz);
a61af66fc99e Initial load
duke
parents:
diff changeset
349 bool is_lab = true;
a61af66fc99e Initial load
duke
parents:
diff changeset
350 if (obj_ptr == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
351 #ifndef PRODUCT
a61af66fc99e Initial load
duke
parents:
diff changeset
352 if (Universe::heap()->promotion_should_fail()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
353 return NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
354 }
a61af66fc99e Initial load
duke
parents:
diff changeset
355 #endif // #ifndef PRODUCT
a61af66fc99e Initial load
duke
parents:
diff changeset
356
a61af66fc99e Initial load
duke
parents:
diff changeset
357 // Slow path:
a61af66fc99e Initial load
duke
parents:
diff changeset
358 if (word_sz * 100 < ParallelGCBufferWastePct * buf->word_sz()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
359 // Is small enough; abandon this buffer and start a new one.
a61af66fc99e Initial load
duke
parents:
diff changeset
360 size_t buf_size = buf->word_sz();
a61af66fc99e Initial load
duke
parents:
diff changeset
361 HeapWord* buf_space =
a61af66fc99e Initial load
duke
parents:
diff changeset
362 TenuredGeneration::par_allocate(buf_size, false);
a61af66fc99e Initial load
duke
parents:
diff changeset
363 if (buf_space == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
364 buf_space = expand_and_allocate(buf_size, false, true /* parallel*/);
a61af66fc99e Initial load
duke
parents:
diff changeset
365 }
a61af66fc99e Initial load
duke
parents:
diff changeset
366 if (buf_space != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
367 buf->retire(false, false);
a61af66fc99e Initial load
duke
parents:
diff changeset
368 buf->set_buf(buf_space);
a61af66fc99e Initial load
duke
parents:
diff changeset
369 obj_ptr = buf->allocate(word_sz);
a61af66fc99e Initial load
duke
parents:
diff changeset
370 assert(obj_ptr != NULL, "Buffer was definitely big enough...");
a61af66fc99e Initial load
duke
parents:
diff changeset
371 }
a61af66fc99e Initial load
duke
parents:
diff changeset
372 };
a61af66fc99e Initial load
duke
parents:
diff changeset
373 // Otherwise, buffer allocation failed; try allocating object
a61af66fc99e Initial load
duke
parents:
diff changeset
374 // individually.
a61af66fc99e Initial load
duke
parents:
diff changeset
375 if (obj_ptr == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
376 obj_ptr = TenuredGeneration::par_allocate(word_sz, false);
a61af66fc99e Initial load
duke
parents:
diff changeset
377 if (obj_ptr == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
378 obj_ptr = expand_and_allocate(word_sz, false, true /* parallel */);
a61af66fc99e Initial load
duke
parents:
diff changeset
379 }
a61af66fc99e Initial load
duke
parents:
diff changeset
380 }
a61af66fc99e Initial load
duke
parents:
diff changeset
381 if (obj_ptr == NULL) return NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
382 }
a61af66fc99e Initial load
duke
parents:
diff changeset
383 assert(obj_ptr != NULL, "program logic");
a61af66fc99e Initial load
duke
parents:
diff changeset
384 Copy::aligned_disjoint_words((HeapWord*)old, obj_ptr, word_sz);
a61af66fc99e Initial load
duke
parents:
diff changeset
385 oop obj = oop(obj_ptr);
a61af66fc99e Initial load
duke
parents:
diff changeset
386 // Restore the mark word copied above.
a61af66fc99e Initial load
duke
parents:
diff changeset
387 obj->set_mark(m);
a61af66fc99e Initial load
duke
parents:
diff changeset
388 return obj;
a61af66fc99e Initial load
duke
parents:
diff changeset
389 }
a61af66fc99e Initial load
duke
parents:
diff changeset
390
a61af66fc99e Initial load
duke
parents:
diff changeset
391 void TenuredGeneration::par_promote_alloc_undo(int thread_num,
a61af66fc99e Initial load
duke
parents:
diff changeset
392 HeapWord* obj,
a61af66fc99e Initial load
duke
parents:
diff changeset
393 size_t word_sz) {
a61af66fc99e Initial load
duke
parents:
diff changeset
394 ParGCAllocBufferWithBOT* buf = _alloc_buffers[thread_num];
a61af66fc99e Initial load
duke
parents:
diff changeset
395 if (buf->contains(obj)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
396 guarantee(buf->contains(obj + word_sz - 1),
a61af66fc99e Initial load
duke
parents:
diff changeset
397 "should contain whole object");
a61af66fc99e Initial load
duke
parents:
diff changeset
398 buf->undo_allocation(obj, word_sz);
a61af66fc99e Initial load
duke
parents:
diff changeset
399 } else {
481
7d7a7c599c17 6578152: fill_region_with_object has usability and safety issues
jcoomes
parents: 196
diff changeset
400 CollectedHeap::fill_with_object(obj, word_sz);
0
a61af66fc99e Initial load
duke
parents:
diff changeset
401 }
a61af66fc99e Initial load
duke
parents:
diff changeset
402 }
a61af66fc99e Initial load
duke
parents:
diff changeset
403
a61af66fc99e Initial load
duke
parents:
diff changeset
404 void TenuredGeneration::par_promote_alloc_done(int thread_num) {
a61af66fc99e Initial load
duke
parents:
diff changeset
405 ParGCAllocBufferWithBOT* buf = _alloc_buffers[thread_num];
a61af66fc99e Initial load
duke
parents:
diff changeset
406 buf->retire(true, ParallelGCRetainPLAB);
a61af66fc99e Initial load
duke
parents:
diff changeset
407 }
a61af66fc99e Initial load
duke
parents:
diff changeset
408
a61af66fc99e Initial load
duke
parents:
diff changeset
409 void TenuredGeneration::retire_alloc_buffers_before_full_gc() {
a61af66fc99e Initial load
duke
parents:
diff changeset
410 if (UseParNewGC) {
a61af66fc99e Initial load
duke
parents:
diff changeset
411 for (uint i = 0; i < ParallelGCThreads; i++) {
a61af66fc99e Initial load
duke
parents:
diff changeset
412 _alloc_buffers[i]->retire(true /*end_of_gc*/, false /*retain*/);
a61af66fc99e Initial load
duke
parents:
diff changeset
413 }
a61af66fc99e Initial load
duke
parents:
diff changeset
414 }
a61af66fc99e Initial load
duke
parents:
diff changeset
415 }
a61af66fc99e Initial load
duke
parents:
diff changeset
416
a61af66fc99e Initial load
duke
parents:
diff changeset
417 // Verify that any retained parallel allocation buffers do not
a61af66fc99e Initial load
duke
parents:
diff changeset
418 // intersect with dirty cards.
a61af66fc99e Initial load
duke
parents:
diff changeset
419 void TenuredGeneration::verify_alloc_buffers_clean() {
a61af66fc99e Initial load
duke
parents:
diff changeset
420 if (UseParNewGC) {
a61af66fc99e Initial load
duke
parents:
diff changeset
421 for (uint i = 0; i < ParallelGCThreads; i++) {
6
73e96e5c30df 6624765: Guarantee failure "Unexpected dirty card found"
jmasa
parents: 0
diff changeset
422 _rs->verify_aligned_region_empty(_alloc_buffers[i]->range());
0
a61af66fc99e Initial load
duke
parents:
diff changeset
423 }
a61af66fc99e Initial load
duke
parents:
diff changeset
424 }
a61af66fc99e Initial load
duke
parents:
diff changeset
425 }
6
73e96e5c30df 6624765: Guarantee failure "Unexpected dirty card found"
jmasa
parents: 0
diff changeset
426
8001
db9981fd3124 8005915: Unify SERIALGC and INCLUDE_ALTERNATE_GCS
jprovino
parents: 7451
diff changeset
427 #else // INCLUDE_ALL_GCS
0
a61af66fc99e Initial load
duke
parents:
diff changeset
428 void TenuredGeneration::retire_alloc_buffers_before_full_gc() {}
a61af66fc99e Initial load
duke
parents:
diff changeset
429 void TenuredGeneration::verify_alloc_buffers_clean() {}
8001
db9981fd3124 8005915: Unify SERIALGC and INCLUDE_ALTERNATE_GCS
jprovino
parents: 7451
diff changeset
430 #endif // INCLUDE_ALL_GCS
0
a61af66fc99e Initial load
duke
parents:
diff changeset
431
1888
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
432 bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
433 size_t available = max_contiguous_available();
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
434 size_t av_promo = (size_t)gc_stats()->avg_promoted()->padded_average();
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
435 bool res = (available >= av_promo) || (available >= max_promotion_in_bytes);
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
436 if (PrintGC && Verbose) {
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
437 gclog_or_tty->print_cr(
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
438 "Tenured: promo attempt is%s safe: available("SIZE_FORMAT") %s av_promo("SIZE_FORMAT"),"
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
439 "max_promo("SIZE_FORMAT")",
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
440 res? "":" not", available, res? ">=":"<",
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
441 av_promo, max_promotion_in_bytes);
0
a61af66fc99e Initial load
duke
parents:
diff changeset
442 }
1888
a7214d79fcf1 6896603: CMS/GCH: collection_attempt_is_safe() ergo should use more recent data
ysr
parents: 1552
diff changeset
443 return res;
0
a61af66fc99e Initial load
duke
parents:
diff changeset
444 }