Fri, 10 Oct 2014 15:51:58 +0200
8059758: Footprint regressions with JDK-8038423
Summary: Changes in JDK-8038423 always initialize (zero out) virtual memory used for auxiliary data structures. This causes a footprint regression for G1 in startup benchmarks. This is because they do not touch that memory at all, so the operating system does not actually commit these pages. The fix is to, if the initialization value of the data structures matches the default value of just committed memory (=0), do not do anything.
Reviewed-by: jwilhelm, brutisso
1 /*
2 * Copyright (c) 2014, 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 */
25 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP
26 #define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP
28 //
29 // String Deduplication
30 //
31 // String deduplication aims to reduce the heap live-set by deduplicating identical
32 // instances of String so that they share the same backing character array.
33 //
34 // The deduplication process is divided in two main parts, 1) finding the objects to
35 // deduplicate, and 2) deduplicating those objects. The first part is done as part of
36 // a normal GC cycle when objects are marked or evacuated. At this time a check is
37 // applied on each object to check if it is a candidate for deduplication. If so, the
38 // object is placed on the deduplication queue for later processing. The second part,
39 // processing the objects on the deduplication queue, is a concurrent phase which
40 // starts right after the stop-the-wold marking/evacuation phase. This phase is
41 // executed by the deduplication thread, which pulls deduplication candidates of the
42 // deduplication queue and tries to deduplicate them.
43 //
44 // A deduplication hashtable is used to keep track of all unique character arrays
45 // used by String objects. When deduplicating, a lookup is made in this table to see
46 // if there is already an identical character array somewhere on the heap. If so, the
47 // String object is adjusted to point to that character array, releasing the reference
48 // to the original array allowing it to eventually be garbage collected. If the lookup
49 // fails the character array is instead inserted into the hashtable so that this array
50 // can be shared at some point in the future.
51 //
52 // Candidate selection
53 //
54 // An object is considered a deduplication candidate if all of the following
55 // statements are true:
56 //
57 // - The object is an instance of java.lang.String
58 //
59 // - The object is being evacuated from a young heap region
60 //
61 // - The object is being evacuated to a young/survivor heap region and the
62 // object's age is equal to the deduplication age threshold
63 //
64 // or
65 //
66 // The object is being evacuated to an old heap region and the object's age is
67 // less than the deduplication age threshold
68 //
69 // Once an string object has been promoted to an old region, or its age is higher
70 // than the deduplication age threshold, is will never become a candidate again.
71 // This approach avoids making the same object a candidate more than once.
72 //
73 // Interned strings are a bit special. They are explicitly deduplicated just before
74 // being inserted into the StringTable (to avoid counteracting C2 optimizations done
75 // on string literals), then they also become deduplication candidates if they reach
76 // the deduplication age threshold or are evacuated to an old heap region. The second
77 // attempt to deduplicate such strings will be in vain, but we have no fast way of
78 // filtering them out. This has not shown to be a problem, as the number of interned
79 // strings is usually dwarfed by the number of normal (non-interned) strings.
80 //
81 // For additional information on string deduplication, please see JEP 192,
82 // http://openjdk.java.net/jeps/192
83 //
85 #include "memory/allocation.hpp"
86 #include "oops/oop.hpp"
88 class OopClosure;
89 class BoolObjectClosure;
90 class ThreadClosure;
91 class outputStream;
92 class G1StringDedupTable;
94 //
95 // Main interface for interacting with string deduplication.
96 //
97 class G1StringDedup : public AllStatic {
98 private:
99 // Single state for checking if both G1 and string deduplication is enabled.
100 static bool _enabled;
102 // Candidate selection policies, returns true if the given object is
103 // candidate for string deduplication.
104 static bool is_candidate_from_mark(oop obj);
105 static bool is_candidate_from_evacuation(bool from_young, bool to_young, oop obj);
107 public:
108 // Returns true if both G1 and string deduplication is enabled.
109 static bool is_enabled() {
110 return _enabled;
111 }
113 // Initialize string deduplication.
114 static void initialize();
116 // Stop the deduplication thread.
117 static void stop();
119 // Immediately deduplicates the given String object, bypassing the
120 // the deduplication queue.
121 static void deduplicate(oop java_string);
123 // Enqueues a deduplication candidate for later processing by the deduplication
124 // thread. Before enqueuing, these functions apply the appropriate candidate
125 // selection policy to filters out non-candidates.
126 static void enqueue_from_mark(oop java_string);
127 static void enqueue_from_evacuation(bool from_young, bool to_young,
128 unsigned int queue, oop java_string);
130 static void oops_do(OopClosure* keep_alive);
131 static void unlink(BoolObjectClosure* is_alive);
132 static void unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive,
133 bool allow_resize_and_rehash = true);
135 static void threads_do(ThreadClosure* tc);
136 static void print_worker_threads_on(outputStream* st);
137 static void verify();
138 };
140 //
141 // This closure encapsulates the state and the closures needed when scanning
142 // the deduplication queue and table during the unlink_or_oops_do() operation.
143 // A single instance of this closure is created and then shared by all worker
144 // threads participating in the scan. The _next_queue and _next_bucket fields
145 // provide a simple mechanism for GC workers to claim exclusive access to a
146 // queue or a table partition.
147 //
148 class G1StringDedupUnlinkOrOopsDoClosure : public StackObj {
149 private:
150 BoolObjectClosure* _is_alive;
151 OopClosure* _keep_alive;
152 G1StringDedupTable* _resized_table;
153 G1StringDedupTable* _rehashed_table;
154 size_t _next_queue;
155 size_t _next_bucket;
157 public:
158 G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
159 OopClosure* keep_alive,
160 bool allow_resize_and_rehash);
161 ~G1StringDedupUnlinkOrOopsDoClosure();
163 bool is_resizing() {
164 return _resized_table != NULL;
165 }
167 G1StringDedupTable* resized_table() {
168 return _resized_table;
169 }
171 bool is_rehashing() {
172 return _rehashed_table != NULL;
173 }
175 // Atomically claims the next available queue for exclusive access by
176 // the current thread. Returns the queue number of the claimed queue.
177 size_t claim_queue() {
178 return (size_t)Atomic::add_ptr(1, &_next_queue) - 1;
179 }
181 // Atomically claims the next available table partition for exclusive
182 // access by the current thread. Returns the table bucket number where
183 // the claimed partition starts.
184 size_t claim_table_partition(size_t partition_size) {
185 return (size_t)Atomic::add_ptr(partition_size, &_next_bucket) - partition_size;
186 }
188 // Applies and returns the result from the is_alive closure, or
189 // returns true if no such closure was provided.
190 bool is_alive(oop o) {
191 if (_is_alive != NULL) {
192 return _is_alive->do_object_b(o);
193 }
194 return true;
195 }
197 // Applies the keep_alive closure, or does nothing if no such
198 // closure was provided.
199 void keep_alive(oop* p) {
200 if (_keep_alive != NULL) {
201 _keep_alive->do_oop(p);
202 }
203 }
204 };
206 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP