26 #include "classfile/altHashing.hpp" |
26 #include "classfile/altHashing.hpp" |
27 #include "classfile/javaClasses.hpp" |
27 #include "classfile/javaClasses.hpp" |
28 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" |
28 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" |
29 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" |
29 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" |
30 #include "gc_implementation/g1/g1StringDedupTable.hpp" |
30 #include "gc_implementation/g1/g1StringDedupTable.hpp" |
|
31 #include "gc_implementation/shared/concurrentGCThread.hpp" |
31 #include "memory/gcLocker.hpp" |
32 #include "memory/gcLocker.hpp" |
32 #include "memory/padded.inline.hpp" |
33 #include "memory/padded.inline.hpp" |
33 #include "oops/typeArrayOop.hpp" |
34 #include "oops/typeArrayOop.hpp" |
34 #include "runtime/mutexLocker.hpp" |
35 #include "runtime/mutexLocker.hpp" |
35 |
36 |
36 // |
37 // |
37 // Freelist in the deduplication table entry cache. Links table |
38 // List of deduplication table entries. Links table |
38 // entries together using their _next fields. |
39 // entries together using their _next fields. |
39 // |
40 // |
40 class G1StringDedupEntryFreeList : public CHeapObj<mtGC> { |
41 class G1StringDedupEntryList : public CHeapObj<mtGC> { |
41 private: |
42 private: |
42 G1StringDedupEntry* _list; |
43 G1StringDedupEntry* _list; |
43 size_t _length; |
44 size_t _length; |
44 |
45 |
45 public: |
46 public: |
46 G1StringDedupEntryFreeList() : |
47 G1StringDedupEntryList() : |
47 _list(NULL), |
48 _list(NULL), |
48 _length(0) { |
49 _length(0) { |
49 } |
50 } |
50 |
51 |
51 void add(G1StringDedupEntry* entry) { |
52 void add(G1StringDedupEntry* entry) { |
82 // Allocations are synchronized by StringDedupTable_lock as part of a table |
89 // Allocations are synchronized by StringDedupTable_lock as part of a table |
83 // modification. |
90 // modification. |
84 // |
91 // |
85 class G1StringDedupEntryCache : public CHeapObj<mtGC> { |
92 class G1StringDedupEntryCache : public CHeapObj<mtGC> { |
86 private: |
93 private: |
87 // One freelist per GC worker to allow lock less freeing of |
94 // One cache/overflow list per GC worker to allow lock less freeing of |
88 // entries while doing a parallel scan of the table. Using |
95 // entries while doing a parallel scan of the table. Using PaddedEnd to |
89 // PaddedEnd to avoid false sharing. |
96 // avoid false sharing. |
90 PaddedEnd<G1StringDedupEntryFreeList>* _lists; |
97 size_t _nlists; |
91 size_t _nlists; |
98 size_t _max_list_length; |
|
99 PaddedEnd<G1StringDedupEntryList>* _cached; |
|
100 PaddedEnd<G1StringDedupEntryList>* _overflowed; |
92 |
101 |
93 public: |
102 public: |
94 G1StringDedupEntryCache(); |
103 G1StringDedupEntryCache(size_t max_size); |
95 ~G1StringDedupEntryCache(); |
104 ~G1StringDedupEntryCache(); |
96 |
105 |
97 // Get a table entry from the cache freelist, or allocate a new |
106 // Set max number of table entries to cache. |
98 // entry if the cache is empty. |
107 void set_max_size(size_t max_size); |
|
108 |
|
109 // Get a table entry from the cache, or allocate a new entry if the cache is empty. |
99 G1StringDedupEntry* alloc(); |
110 G1StringDedupEntry* alloc(); |
100 |
111 |
101 // Insert a table entry into the cache freelist. |
112 // Insert a table entry into the cache. |
102 void free(G1StringDedupEntry* entry, uint worker_id); |
113 void free(G1StringDedupEntry* entry, uint worker_id); |
103 |
114 |
104 // Returns current number of entries in the cache. |
115 // Returns current number of entries in the cache. |
105 size_t size(); |
116 size_t size(); |
106 |
117 |
107 // If the cache has grown above the given max size, trim it down |
118 // Deletes overflowed entries. |
108 // and deallocate the memory occupied by trimmed of entries. |
119 void delete_overflowed(); |
109 void trim(size_t max_size); |
|
110 }; |
120 }; |
111 |
121 |
112 G1StringDedupEntryCache::G1StringDedupEntryCache() { |
122 G1StringDedupEntryCache::G1StringDedupEntryCache(size_t max_size) : |
113 _nlists = MAX2(ParallelGCThreads, (size_t)1); |
123 _nlists(MAX2(ParallelGCThreads, (size_t)1)), |
114 _lists = PaddedArray<G1StringDedupEntryFreeList, mtGC>::create_unfreeable((uint)_nlists); |
124 _max_list_length(0), |
|
125 _cached(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)), |
|
126 _overflowed(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)) { |
|
127 set_max_size(max_size); |
115 } |
128 } |
116 |
129 |
117 G1StringDedupEntryCache::~G1StringDedupEntryCache() { |
130 G1StringDedupEntryCache::~G1StringDedupEntryCache() { |
118 ShouldNotReachHere(); |
131 ShouldNotReachHere(); |
119 } |
132 } |
120 |
133 |
|
134 void G1StringDedupEntryCache::set_max_size(size_t size) { |
|
135 _max_list_length = size / _nlists; |
|
136 } |
|
137 |
121 G1StringDedupEntry* G1StringDedupEntryCache::alloc() { |
138 G1StringDedupEntry* G1StringDedupEntryCache::alloc() { |
122 for (size_t i = 0; i < _nlists; i++) { |
139 for (size_t i = 0; i < _nlists; i++) { |
123 G1StringDedupEntry* entry = _lists[i].remove(); |
140 G1StringDedupEntry* entry = _cached[i].remove(); |
124 if (entry != NULL) { |
141 if (entry != NULL) { |
125 return entry; |
142 return entry; |
126 } |
143 } |
127 } |
144 } |
128 return new G1StringDedupEntry(); |
145 return new G1StringDedupEntry(); |
129 } |
146 } |
130 |
147 |
131 void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) { |
148 void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) { |
132 assert(entry->obj() != NULL, "Double free"); |
149 assert(entry->obj() != NULL, "Double free"); |
133 assert(worker_id < _nlists, "Invalid worker id"); |
150 assert(worker_id < _nlists, "Invalid worker id"); |
|
151 |
134 entry->set_obj(NULL); |
152 entry->set_obj(NULL); |
135 entry->set_hash(0); |
153 entry->set_hash(0); |
136 _lists[worker_id].add(entry); |
154 |
|
155 if (_cached[worker_id].length() < _max_list_length) { |
|
156 // Cache is not full |
|
157 _cached[worker_id].add(entry); |
|
158 } else { |
|
159 // Cache is full, add to overflow list for later deletion |
|
160 _overflowed[worker_id].add(entry); |
|
161 } |
137 } |
162 } |
138 |
163 |
139 size_t G1StringDedupEntryCache::size() { |
164 size_t G1StringDedupEntryCache::size() { |
140 size_t size = 0; |
165 size_t size = 0; |
141 for (size_t i = 0; i < _nlists; i++) { |
166 for (size_t i = 0; i < _nlists; i++) { |
142 size += _lists[i].length(); |
167 size += _cached[i].length(); |
143 } |
168 } |
144 return size; |
169 return size; |
145 } |
170 } |
146 |
171 |
147 void G1StringDedupEntryCache::trim(size_t max_size) { |
172 void G1StringDedupEntryCache::delete_overflowed() { |
148 size_t cache_size = 0; |
173 double start = os::elapsedTime(); |
|
174 uintx count = 0; |
|
175 |
149 for (size_t i = 0; i < _nlists; i++) { |
176 for (size_t i = 0; i < _nlists; i++) { |
150 G1StringDedupEntryFreeList* list = &_lists[i]; |
177 G1StringDedupEntry* entry; |
151 cache_size += list->length(); |
178 |
152 while (cache_size > max_size) { |
179 { |
153 G1StringDedupEntry* entry = list->remove(); |
180 // The overflow list can be modified during safepoints, therefore |
154 assert(entry != NULL, "Should not be null"); |
181 // we temporarily join the suspendible thread set while removing |
155 cache_size--; |
182 // all entries from the list. |
|
183 SuspendibleThreadSetJoiner sts_join; |
|
184 entry = _overflowed[i].remove_all(); |
|
185 } |
|
186 |
|
187 // Delete all entries |
|
188 while (entry != NULL) { |
|
189 G1StringDedupEntry* next = entry->next(); |
156 delete entry; |
190 delete entry; |
157 } |
191 entry = next; |
|
192 count++; |
|
193 } |
|
194 } |
|
195 |
|
196 double end = os::elapsedTime(); |
|
197 if (PrintStringDeduplicationStatistics) { |
|
198 gclog_or_tty->print_cr("[GC concurrent-string-deduplication, deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT "]", count, end - start); |
158 } |
199 } |
159 } |
200 } |
160 |
201 |
161 G1StringDedupTable* G1StringDedupTable::_table = NULL; |
202 G1StringDedupTable* G1StringDedupTable::_table = NULL; |
162 G1StringDedupEntryCache* G1StringDedupTable::_entry_cache = NULL; |
203 G1StringDedupEntryCache* G1StringDedupTable::_entry_cache = NULL; |