提交 0f5fc07e 编写于 作者: P pliden

8029075: String deduplication in G1

Summary: Implementation of JEP 192, http://openjdk.java.net/jeps/192
Reviewed-by: brutisso, tschatzl, coleenp
上级 e19f4721
......@@ -87,7 +87,8 @@ ifeq ($(INCLUDE_ALL_GCS), false)
g1BlockOffsetTable.cpp g1CardCounts.cpp g1CollectedHeap.cpp g1CollectorPolicy.cpp \
g1ErgoVerbose.cpp g1GCPhaseTimes.cpp g1HRPrinter.cpp g1HotCardCache.cpp g1Log.cpp \
g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp g1OopClosures.cpp \
g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \
g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1StringDedup.cpp g1StringDedupStat.cpp \
g1StringDedupTable.cpp g1StringDedupThread.cpp g1StringDedupQueue.cpp g1_globals.cpp heapRegion.cpp \
g1BiasedArray.cpp heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \
ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp g1CodeCacheRemSet.cpp \
adjoiningGenerations.cpp adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp \
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -61,10 +61,6 @@ class java_lang_String : AllStatic {
static Handle basic_create(int length, TRAPS);
static void set_value( oop string, typeArrayOop buffer) {
assert(initialized, "Must be initialized");
string->obj_field_put(value_offset, (oop)buffer);
}
static void set_offset(oop string, int offset) {
assert(initialized, "Must be initialized");
if (offset_offset > 0) {
......@@ -122,12 +118,26 @@ class java_lang_String : AllStatic {
return hash_offset;
}
static void set_value(oop string, typeArrayOop buffer) {
assert(initialized && (value_offset > 0), "Must be initialized");
string->obj_field_put(value_offset, (oop)buffer);
}
static void set_hash(oop string, unsigned int hash) {
assert(initialized && (hash_offset > 0), "Must be initialized");
string->int_field_put(hash_offset, hash);
}
// Accessors
static typeArrayOop value(oop java_string) {
assert(initialized && (value_offset > 0), "Must be initialized");
assert(is_instance(java_string), "must be java_string");
return (typeArrayOop) java_string->obj_field(value_offset);
}
static unsigned int hash(oop java_string) {
assert(initialized && (hash_offset > 0), "Must be initialized");
assert(is_instance(java_string), "must be java_string");
return java_string->int_field(hash_offset);
}
static int offset(oop java_string) {
assert(initialized, "Must be initialized");
assert(is_instance(java_string), "must be java_string");
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -35,6 +35,9 @@
#include "oops/oop.inline2.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/hashtable.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/g1StringDedup.hpp"
#endif
// --------------------------------------------------------------------------
......@@ -728,6 +731,15 @@ oop StringTable::intern(Handle string_or_null, jchar* name,
string = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
}
#if INCLUDE_ALL_GCS
if (G1StringDedup::is_enabled()) {
// Deduplicate the string before it is interned. Note that we should never
// deduplicate a string after it has been interned. Doing so will counteract
// compiler optimizations done on e.g. interned string literals.
G1StringDedup::deduplicate(string());
}
#endif
// Grab the StringTable_lock before getting the_table() because it could
// change at safepoint.
MutexLocker ml(StringTable_lock, THREAD);
......
......@@ -39,6 +39,7 @@
#include "gc_implementation/g1/g1MarkSweep.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/g1RemSet.inline.hpp"
#include "gc_implementation/g1/g1StringDedup.hpp"
#include "gc_implementation/g1/g1YCTypes.hpp"
#include "gc_implementation/g1/heapRegion.inline.hpp"
#include "gc_implementation/g1/heapRegionRemSet.hpp"
......@@ -2173,6 +2174,8 @@ jint G1CollectedHeap::initialize() {
// values in the heap have been properly initialized.
_g1mm = new G1MonitoringSupport(this);
G1StringDedup::initialize();
return JNI_OK;
}
......@@ -3475,6 +3478,11 @@ void G1CollectedHeap::verify(bool silent, VerifyOption vo) {
if (!silent) gclog_or_tty->print("RemSet ");
rem_set()->verify();
if (G1StringDedup::is_enabled()) {
if (!silent) gclog_or_tty->print("StrDedup ");
G1StringDedup::verify();
}
if (failures) {
gclog_or_tty->print_cr("Heap:");
// It helps to have the per-region information in the output to
......@@ -3492,8 +3500,13 @@ void G1CollectedHeap::verify(bool silent, VerifyOption vo) {
}
guarantee(!failures, "there should not have been any failures");
} else {
if (!silent)
gclog_or_tty->print("(SKIPPING roots, heapRegionSets, heapRegions, remset) ");
if (!silent) {
gclog_or_tty->print("(SKIPPING Roots, HeapRegionSets, HeapRegions, RemSet");
if (G1StringDedup::is_enabled()) {
gclog_or_tty->print(", StrDedup");
}
gclog_or_tty->print(") ");
}
}
}
......@@ -3586,6 +3599,9 @@ void G1CollectedHeap::print_gc_threads_on(outputStream* st) const {
st->cr();
_cm->print_worker_threads_on(st);
_cg1r->print_worker_threads_on(st);
if (G1StringDedup::is_enabled()) {
G1StringDedup::print_worker_threads_on(st);
}
}
void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const {
......@@ -3594,6 +3610,9 @@ void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const {
}
tc->do_thread(_cmThread);
_cg1r->threads_do(tc);
if (G1StringDedup::is_enabled()) {
G1StringDedup::threads_do(tc);
}
}
void G1CollectedHeap::print_tracing_info() const {
......@@ -4774,6 +4793,13 @@ oop G1ParScanThreadState::copy_to_survivor_space(oop const old) {
obj->set_mark(m);
}
if (G1StringDedup::is_enabled()) {
G1StringDedup::enqueue_from_evacuation(from_region->is_young(),
to_region->is_young(),
queue_num(),
obj);
}
size_t* surv_young_words = surviving_young_words();
surv_young_words[young_index] += word_sz;
......@@ -5249,6 +5275,10 @@ void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive
g1_unlink_task.strings_processed(), g1_unlink_task.strings_removed(),
g1_unlink_task.symbols_processed(), g1_unlink_task.symbols_removed());
}
if (G1StringDedup::is_enabled()) {
G1StringDedup::unlink(is_alive);
}
}
class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure {
......@@ -5872,6 +5902,9 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
G1STWIsAliveClosure is_alive(this);
G1KeepAliveClosure keep_alive(this);
JNIHandles::weak_oops_do(&is_alive, &keep_alive);
if (G1StringDedup::is_enabled()) {
G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive);
}
}
release_gc_alloc_regions(n_workers, evacuation_info);
......@@ -6352,9 +6385,10 @@ void G1CollectedHeap::tear_down_region_sets(bool free_list_only) {
TearDownRegionSetsClosure cl(&_old_set);
heap_region_iterate(&cl);
// Need to do this after the heap iteration to be able to
// recognize the young regions and ignore them during the iteration.
_young_list->empty_list();
// Note that emptying the _young_list is postponed and instead done as
// the first step when rebuilding the regions sets again. The reason for
// this is that during a full GC string deduplication needs to know if
// a collected region was young or old when the full GC was initiated.
}
_free_list.remove_all();
}
......@@ -6408,6 +6442,10 @@ public:
void G1CollectedHeap::rebuild_region_sets(bool free_list_only) {
assert_at_safepoint(true /* should_be_vm_thread */);
if (!free_list_only) {
_young_list->empty_list();
}
RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_free_list);
heap_region_iterate(&cl);
......
......@@ -27,6 +27,7 @@
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1GCPhaseTimes.hpp"
#include "gc_implementation/g1/g1Log.hpp"
#include "gc_implementation/g1/g1StringDedup.hpp"
// Helper class for avoiding interleaved logging
class LineBuffer: public StackObj {
......@@ -168,7 +169,9 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) :
_last_termination_attempts(_max_gc_threads, SIZE_FORMAT),
_last_gc_worker_end_times_ms(_max_gc_threads, "%.1lf", false),
_last_gc_worker_times_ms(_max_gc_threads, "%.1lf"),
_last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf")
_last_gc_worker_other_times_ms(_max_gc_threads, "%.1lf"),
_cur_string_dedup_queue_fixup_worker_times_ms(_max_gc_threads, "%.1lf"),
_cur_string_dedup_table_fixup_worker_times_ms(_max_gc_threads, "%.1lf")
{
assert(max_gc_threads > 0, "Must have some GC threads");
}
......@@ -229,6 +232,16 @@ void G1GCPhaseTimes::note_gc_end() {
_last_gc_worker_other_times_ms.verify();
}
void G1GCPhaseTimes::note_string_dedup_fixup_start() {
_cur_string_dedup_queue_fixup_worker_times_ms.reset();
_cur_string_dedup_table_fixup_worker_times_ms.reset();
}
void G1GCPhaseTimes::note_string_dedup_fixup_end() {
_cur_string_dedup_queue_fixup_worker_times_ms.verify();
_cur_string_dedup_table_fixup_worker_times_ms.verify();
}
void G1GCPhaseTimes::print_stats(int level, const char* str, double value) {
LineBuffer(level).append_and_print_cr("[%s: %.1lf ms]", str, value);
}
......@@ -253,6 +266,11 @@ double G1GCPhaseTimes::accounted_time_ms() {
// Strong code root purge time
misc_time_ms += _cur_strong_code_root_purge_time_ms;
if (G1StringDedup::is_enabled()) {
// String dedup fixup time
misc_time_ms += _cur_string_dedup_fixup_time_ms;
}
// Subtract the time taken to clean the card table from the
// current value of "other time"
misc_time_ms += _cur_clear_ct_time_ms;
......@@ -303,6 +321,11 @@ void G1GCPhaseTimes::print(double pause_time_sec) {
print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms);
print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms);
print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms);
if (G1StringDedup::is_enabled()) {
print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads);
_cur_string_dedup_queue_fixup_worker_times_ms.print(2, "Queue Fixup (ms)");
_cur_string_dedup_table_fixup_worker_times_ms.print(2, "Table Fixup (ms)");
}
print_stats(1, "Clear CT", _cur_clear_ct_time_ms);
double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms();
print_stats(1, "Other", misc_time_ms);
......
......@@ -137,6 +137,10 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
double _cur_evac_fail_restore_remsets;
double _cur_evac_fail_remove_self_forwards;
double _cur_string_dedup_fixup_time_ms;
WorkerDataArray<double> _cur_string_dedup_queue_fixup_worker_times_ms;
WorkerDataArray<double> _cur_string_dedup_table_fixup_worker_times_ms;
double _cur_clear_ct_time_ms;
double _cur_ref_proc_time_ms;
double _cur_ref_enq_time_ms;
......@@ -246,6 +250,21 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
_cur_evac_fail_remove_self_forwards = ms;
}
void note_string_dedup_fixup_start();
void note_string_dedup_fixup_end();
void record_string_dedup_fixup_time(double ms) {
_cur_string_dedup_fixup_time_ms = ms;
}
void record_string_dedup_queue_fixup_worker_time(uint worker_id, double ms) {
_cur_string_dedup_queue_fixup_worker_times_ms.set(worker_id, ms);
}
void record_string_dedup_table_fixup_worker_time(uint worker_id, double ms) {
_cur_string_dedup_table_fixup_worker_times_ms.set(worker_id, ms);
}
void record_ref_proc_time(double ms) {
_cur_ref_proc_time_ms = ms;
}
......
/*
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -31,6 +31,7 @@
#include "code/icBuffer.hpp"
#include "gc_implementation/g1/g1Log.hpp"
#include "gc_implementation/g1/g1MarkSweep.hpp"
#include "gc_implementation/g1/g1StringDedup.hpp"
#include "gc_implementation/shared/gcHeapSummary.hpp"
#include "gc_implementation/shared/gcTimer.hpp"
#include "gc_implementation/shared/gcTrace.hpp"
......@@ -320,6 +321,10 @@ void G1MarkSweep::mark_sweep_phase3() {
// have been cleared if they pointed to non-surviving objects.)
g1h->g1_process_weak_roots(&GenMarkSweep::adjust_pointer_closure);
if (G1StringDedup::is_enabled()) {
G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure);
}
GenMarkSweep::adjust_marks();
G1AdjustPointersClosure blk;
......
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1GCPhaseTimes.hpp"
#include "gc_implementation/g1/g1StringDedup.hpp"
#include "gc_implementation/g1/g1StringDedupQueue.hpp"
#include "gc_implementation/g1/g1StringDedupStat.hpp"
#include "gc_implementation/g1/g1StringDedupTable.hpp"
#include "gc_implementation/g1/g1StringDedupThread.hpp"
bool G1StringDedup::_enabled = false;
void G1StringDedup::initialize() {
assert(UseG1GC, "String deduplication only available with G1");
if (UseStringDeduplication) {
_enabled = true;
G1StringDedupQueue::create();
G1StringDedupTable::create();
G1StringDedupThread::create();
}
}
bool G1StringDedup::is_candidate_from_mark(oop obj) {
if (java_lang_String::is_instance(obj)) {
bool from_young = G1CollectedHeap::heap()->heap_region_containing_raw(obj)->is_young();
if (from_young && obj->age() < StringDeduplicationAgeThreshold) {
// Candidate found. String is being evacuated from young to old but has not
// reached the deduplication age threshold, i.e. has not previously been a
// candidate during its life in the young generation.
return true;
}
}
// Not a candidate
return false;
}
void G1StringDedup::enqueue_from_mark(oop java_string) {
assert(is_enabled(), "String deduplication not enabled");
if (is_candidate_from_mark(java_string)) {
G1StringDedupQueue::push(0 /* worker_id */, java_string);
}
}
bool G1StringDedup::is_candidate_from_evacuation(bool from_young, bool to_young, oop obj) {
if (from_young && java_lang_String::is_instance(obj)) {
if (to_young && obj->age() == StringDeduplicationAgeThreshold) {
// Candidate found. String is being evacuated from young to young and just
// reached the deduplication age threshold.
return true;
}
if (!to_young && obj->age() < StringDeduplicationAgeThreshold) {
// Candidate found. String is being evacuated from young to old but has not
// reached the deduplication age threshold, i.e. has not previously been a
// candidate during its life in the young generation.
return true;
}
}
// Not a candidate
return false;
}
void G1StringDedup::enqueue_from_evacuation(bool from_young, bool to_young, uint worker_id, oop java_string) {
assert(is_enabled(), "String deduplication not enabled");
if (is_candidate_from_evacuation(from_young, to_young, java_string)) {
G1StringDedupQueue::push(worker_id, java_string);
}
}
void G1StringDedup::deduplicate(oop java_string) {
assert(is_enabled(), "String deduplication not enabled");
G1StringDedupStat dummy; // Statistics from this path is never used
G1StringDedupTable::deduplicate(java_string, dummy);
}
void G1StringDedup::oops_do(OopClosure* keep_alive) {
assert(is_enabled(), "String deduplication not enabled");
unlink_or_oops_do(NULL, keep_alive);
}
void G1StringDedup::unlink(BoolObjectClosure* is_alive) {
assert(is_enabled(), "String deduplication not enabled");
// Don't allow a potential resize or rehash during unlink, as the unlink
// operation itself might remove enough entries to invalidate such a decision.
unlink_or_oops_do(is_alive, NULL, false /* allow_resize_and_rehash */);
}
//
// Task for parallel unlink_or_oops_do() operation on the deduplication queue
// and table.
//
class G1StringDedupUnlinkOrOopsDoTask : public AbstractGangTask {
private:
G1StringDedupUnlinkOrOopsDoClosure _cl;
public:
G1StringDedupUnlinkOrOopsDoTask(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
bool allow_resize_and_rehash) :
AbstractGangTask("G1StringDedupUnlinkOrOopsDoTask"),
_cl(is_alive, keep_alive, allow_resize_and_rehash) {
}
virtual void work(uint worker_id) {
double queue_fixup_start = os::elapsedTime();
G1StringDedupQueue::unlink_or_oops_do(&_cl);
double table_fixup_start = os::elapsedTime();
G1StringDedupTable::unlink_or_oops_do(&_cl, worker_id);
double queue_fixup_time_ms = (table_fixup_start - queue_fixup_start) * 1000.0;
double table_fixup_time_ms = (os::elapsedTime() - table_fixup_start) * 1000.0;
G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy();
g1p->phase_times()->record_string_dedup_queue_fixup_worker_time(worker_id, queue_fixup_time_ms);
g1p->phase_times()->record_string_dedup_table_fixup_worker_time(worker_id, table_fixup_time_ms);
}
};
void G1StringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, bool allow_resize_and_rehash) {
assert(is_enabled(), "String deduplication not enabled");
G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy();
g1p->phase_times()->note_string_dedup_fixup_start();
double fixup_start = os::elapsedTime();
G1StringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash);
if (G1CollectedHeap::use_parallel_gc_threads()) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
g1h->set_par_threads();
g1h->workers()->run_task(&task);
g1h->set_par_threads(0);
} else {
task.work(0);
}
double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0;
g1p->phase_times()->record_string_dedup_fixup_time(fixup_time_ms);
g1p->phase_times()->note_string_dedup_fixup_end();
}
void G1StringDedup::threads_do(ThreadClosure* tc) {
assert(is_enabled(), "String deduplication not enabled");
tc->do_thread(G1StringDedupThread::thread());
}
void G1StringDedup::print_worker_threads_on(outputStream* st) {
assert(is_enabled(), "String deduplication not enabled");
G1StringDedupThread::thread()->print_on(st);
st->cr();
}
void G1StringDedup::verify() {
assert(is_enabled(), "String deduplication not enabled");
G1StringDedupQueue::verify();
G1StringDedupTable::verify();
}
G1StringDedupUnlinkOrOopsDoClosure::G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
bool allow_resize_and_rehash) :
_is_alive(is_alive),
_keep_alive(keep_alive),
_resized_table(NULL),
_rehashed_table(NULL),
_next_queue(0),
_next_bucket(0) {
if (allow_resize_and_rehash) {
// If both resize and rehash is needed, only do resize. Rehash of
// the table will eventually happen if the situation persists.
_resized_table = G1StringDedupTable::prepare_resize();
if (!is_resizing()) {
_rehashed_table = G1StringDedupTable::prepare_rehash();
}
}
}
G1StringDedupUnlinkOrOopsDoClosure::~G1StringDedupUnlinkOrOopsDoClosure() {
assert(!is_resizing() || !is_rehashing(), "Can not both resize and rehash");
if (is_resizing()) {
G1StringDedupTable::finish_resize(_resized_table);
} else if (is_rehashing()) {
G1StringDedupTable::finish_rehash(_rehashed_table);
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP
//
// String Deduplication
//
// String deduplication aims to reduce the heap live-set by deduplicating identical
// instances of String so that they share the same backing character array.
//
// The deduplication process is divided in two main parts, 1) finding the objects to
// deduplicate, and 2) deduplicating those objects. The first part is done as part of
// a normal GC cycle when objects are marked or evacuated. At this time a check is
// applied on each object to check if it is a candidate for deduplication. If so, the
// object is placed on the deduplication queue for later processing. The second part,
// processing the objects on the deduplication queue, is a concurrent phase which
// starts right after the stop-the-wold marking/evacuation phase. This phase is
// executed by the deduplication thread, which pulls deduplication candidates of the
// deduplication queue and tries to deduplicate them.
//
// A deduplication hashtable is used to keep track of all unique character arrays
// used by String objects. When deduplicating, a lookup is made in this table to see
// if there is already an identical character array somewhere on the heap. If so, the
// String object is adjusted to point to that character array, releasing the reference
// to the original array allowing it to eventually be garbage collected. If the lookup
// fails the character array is instead inserted into the hashtable so that this array
// can be shared at some point in the future.
//
// Candidate selection
//
// An object is considered a deduplication candidate if all of the following
// statements are true:
//
// - The object is an instance of java.lang.String
//
// - The object is being evacuated from a young heap region
//
// - The object is being evacuated to a young/survivor heap region and the
// object's age is equal to the deduplication age threshold
//
// or
//
// The object is being evacuated to an old heap region and the object's age is
// less than the deduplication age threshold
//
// Once an string object has been promoted to an old region, or its age is higher
// than the deduplication age threshold, is will never become a candidate again.
// This approach avoids making the same object a candidate more than once.
//
// Interned strings are a bit special. They are explicitly deduplicated just before
// being inserted into the StringTable (to avoid counteracting C2 optimizations done
// on string literals), then they also become deduplication candidates if they reach
// the deduplication age threshold or are evacuated to an old heap region. The second
// attempt to deduplicate such strings will be in vain, but we have no fast way of
// filtering them out. This has not shown to be a problem, as the number of interned
// strings is usually dwarfed by the number of normal (non-interned) strings.
//
// For additional information on string deduplication, please see JEP 192,
// http://openjdk.java.net/jeps/192
//
#include "memory/allocation.hpp"
#include "oops/oop.hpp"
class OopClosure;
class BoolObjectClosure;
class ThreadClosure;
class outputStream;
class G1StringDedupTable;
//
// Main interface for interacting with string deduplication.
//
class G1StringDedup : public AllStatic {
private:
// Single state for checking if both G1 and string deduplication is enabled.
static bool _enabled;
// Candidate selection policies, returns true if the given object is
// candidate for string deduplication.
static bool is_candidate_from_mark(oop obj);
static bool is_candidate_from_evacuation(bool from_young, bool to_young, oop obj);
public:
// Returns true if both G1 and string deduplication is enabled.
static bool is_enabled() {
return _enabled;
}
static void initialize();
// Immediately deduplicates the given String object, bypassing the
// the deduplication queue.
static void deduplicate(oop java_string);
// Enqueues a deduplication candidate for later processing by the deduplication
// thread. Before enqueuing, these functions apply the appropriate candidate
// selection policy to filters out non-candidates.
static void enqueue_from_mark(oop java_string);
static void enqueue_from_evacuation(bool from_young, bool to_young,
unsigned int queue, oop java_string);
static void oops_do(OopClosure* keep_alive);
static void unlink(BoolObjectClosure* is_alive);
static void unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive,
bool allow_resize_and_rehash = true);
static void threads_do(ThreadClosure* tc);
static void print_worker_threads_on(outputStream* st);
static void verify();
};
//
// This closure encapsulates the state and the closures needed when scanning
// the deduplication queue and table during the unlink_or_oops_do() operation.
// A single instance of this closure is created and then shared by all worker
// threads participating in the scan. The _next_queue and _next_bucket fields
// provide a simple mechanism for GC workers to claim exclusive access to a
// queue or a table partition.
//
class G1StringDedupUnlinkOrOopsDoClosure : public StackObj {
private:
BoolObjectClosure* _is_alive;
OopClosure* _keep_alive;
G1StringDedupTable* _resized_table;
G1StringDedupTable* _rehashed_table;
size_t _next_queue;
size_t _next_bucket;
public:
G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
bool allow_resize_and_rehash);
~G1StringDedupUnlinkOrOopsDoClosure();
bool is_resizing() {
return _resized_table != NULL;
}
G1StringDedupTable* resized_table() {
return _resized_table;
}
bool is_rehashing() {
return _rehashed_table != NULL;
}
// Atomically claims the next available queue for exclusive access by
// the current thread. Returns the queue number of the claimed queue.
size_t claim_queue() {
return (size_t)Atomic::add_ptr(1, &_next_queue) - 1;
}
// Atomically claims the next available table partition for exclusive
// access by the current thread. Returns the table bucket number where
// the claimed partition starts.
size_t claim_table_partition(size_t partition_size) {
return (size_t)Atomic::add_ptr(partition_size, &_next_bucket) - partition_size;
}
// Applies and returns the result from the is_alive closure, or
// returns true if no such closure was provided.
bool is_alive(oop o) {
if (_is_alive != NULL) {
return _is_alive->do_object_b(o);
}
return true;
}
// Applies the keep_alive closure, or does nothing if no such
// closure was provided.
void keep_alive(oop* p) {
if (_keep_alive != NULL) {
_keep_alive->do_oop(p);
}
}
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUP_HPP
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "gc_implementation/g1/g1StringDedupQueue.hpp"
#include "memory/gcLocker.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/stack.inline.hpp"
G1StringDedupQueue* G1StringDedupQueue::_queue = NULL;
const size_t G1StringDedupQueue::_max_size = 1000000; // Max number of elements per queue
const size_t G1StringDedupQueue::_max_cache_size = 0; // Max cache size per queue
G1StringDedupQueue::G1StringDedupQueue() :
_cursor(0),
_empty(true),
_dropped(0) {
_nqueues = MAX2(ParallelGCThreads, (size_t)1);
_queues = NEW_C_HEAP_ARRAY(G1StringDedupWorkerQueue, _nqueues, mtGC);
for (size_t i = 0; i < _nqueues; i++) {
new (_queues + i) G1StringDedupWorkerQueue(G1StringDedupWorkerQueue::default_segment_size(), _max_cache_size, _max_size);
}
}
G1StringDedupQueue::~G1StringDedupQueue() {
ShouldNotReachHere();
}
void G1StringDedupQueue::create() {
assert(_queue == NULL, "One string deduplication queue allowed");
_queue = new G1StringDedupQueue();
}
void G1StringDedupQueue::wait() {
MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
while (_queue->_empty) {
ml.wait(Mutex::_no_safepoint_check_flag);
}
}
void G1StringDedupQueue::push(uint worker_id, oop java_string) {
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");
assert(worker_id < _queue->_nqueues, "Invalid queue");
// Push and notify waiter
G1StringDedupWorkerQueue& worker_queue = _queue->_queues[worker_id];
if (!worker_queue.is_full()) {
worker_queue.push(java_string);
if (_queue->_empty) {
MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
if (_queue->_empty) {
// Mark non-empty and notify waiter
_queue->_empty = false;
ml.notify();
}
}
} else {
// Queue is full, drop the string and update the statistics
Atomic::inc_ptr(&_queue->_dropped);
}
}
oop G1StringDedupQueue::pop() {
assert(!SafepointSynchronize::is_at_safepoint(), "Must not be at safepoint");
No_Safepoint_Verifier nsv;
// Try all queues before giving up
for (size_t tries = 0; tries < _queue->_nqueues; tries++) {
// The cursor indicates where we left of last time
G1StringDedupWorkerQueue* queue = &_queue->_queues[_queue->_cursor];
while (!queue->is_empty()) {
oop obj = queue->pop();
// The oop we pop can be NULL if it was marked
// dead. Just ignore those and pop the next oop.
if (obj != NULL) {
return obj;
}
}
// Try next queue
_queue->_cursor = (_queue->_cursor + 1) % _queue->_nqueues;
}
// Mark empty
_queue->_empty = true;
return NULL;
}
void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl) {
// A worker thread first claims a queue, which ensures exclusive
// access to that queue, then continues to process it.
for (;;) {
// Grab next queue to scan
size_t queue = cl->claim_queue();
if (queue >= _queue->_nqueues) {
// End of queues
break;
}
// Scan the queue
unlink_or_oops_do(cl, queue);
}
}
void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) {
assert(queue < _queue->_nqueues, "Invalid queue");
StackIterator<oop, mtGC> iter(_queue->_queues[queue]);
while (!iter.is_empty()) {
oop* p = iter.next_addr();
if (*p != NULL) {
if (cl->is_alive(*p)) {
cl->keep_alive(p);
} else {
// Clear dead reference
*p = NULL;
}
}
}
}
void G1StringDedupQueue::print_statistics(outputStream* st) {
st->print_cr(
" [Queue]\n"
" [Dropped: "UINTX_FORMAT"]", _queue->_dropped);
}
void G1StringDedupQueue::verify() {
for (size_t i = 0; i < _queue->_nqueues; i++) {
StackIterator<oop, mtGC> iter(_queue->_queues[i]);
while (!iter.is_empty()) {
oop obj = iter.next();
if (obj != NULL) {
guarantee(Universe::heap()->is_in_reserved(obj), "Object must be on the heap");
guarantee(!obj->is_forwarded(), "Object must not be forwarded");
guarantee(java_lang_String::is_instance(obj), "Object must be a String");
}
}
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP
#include "memory/allocation.hpp"
#include "oops/oop.hpp"
#include "utilities/stack.hpp"
class G1StringDedupUnlinkOrOopsDoClosure;
//
// The deduplication queue acts as the communication channel between the stop-the-world
// mark/evacuation phase and the concurrent deduplication phase. Deduplication candidates
// found during mark/evacuation are placed on this queue for later processing in the
// deduplication thread. A queue entry is an oop pointing to a String object (as opposed
// to entries in the deduplication hashtable which points to character arrays).
//
// While users of the queue treat it as a single queue, it is implemented as a set of
// queues, one queue per GC worker thread, to allow lock-free and cache-friendly enqueue
// operations by the GC workers.
//
// The oops in the queue are treated as weak pointers, meaning the objects they point to
// can become unreachable and pruned (cleared) before being popped by the deduplication
// thread.
//
// Pushing to the queue is thread safe (this relies on each thread using a unique worker
// id), but only allowed during a safepoint. Popping from the queue is NOT thread safe
// and can only be done by the deduplication thread outside a safepoint.
//
// The StringDedupQueue_lock is only used for blocking and waking up the deduplication
// thread in case the queue is empty or becomes non-empty, respectively. This lock does
// not otherwise protect the queue content.
//
class G1StringDedupQueue : public CHeapObj<mtGC> {
private:
typedef Stack<oop, mtGC> G1StringDedupWorkerQueue;
static G1StringDedupQueue* _queue;
static const size_t _max_size;
static const size_t _max_cache_size;
G1StringDedupWorkerQueue* _queues;
size_t _nqueues;
size_t _cursor;
volatile bool _empty;
// Statistics counter, only used for logging.
uintx _dropped;
G1StringDedupQueue();
~G1StringDedupQueue();
static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue);
public:
static void create();
// Blocks and waits for the queue to become non-empty.
static void wait();
// Pushes a deduplication candidate onto a specific GC worker queue.
static void push(uint worker_id, oop java_string);
// Pops a deduplication candidate from any queue, returns NULL if
// all queues are empty.
static oop pop();
static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl);
static void print_statistics(outputStream* st);
static void verify();
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPQUEUE_HPP
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc_implementation/g1/g1StringDedupStat.hpp"
G1StringDedupStat::G1StringDedupStat() :
_inspected(0),
_skipped(0),
_hashed(0),
_known(0),
_new(0),
_new_bytes(0),
_deduped(0),
_deduped_bytes(0),
_deduped_young(0),
_deduped_young_bytes(0),
_deduped_old(0),
_deduped_old_bytes(0),
_idle(0),
_exec(0),
_block(0),
_start(0.0),
_idle_elapsed(0.0),
_exec_elapsed(0.0),
_block_elapsed(0.0) {
}
void G1StringDedupStat::add(const G1StringDedupStat& stat) {
_inspected += stat._inspected;
_skipped += stat._skipped;
_hashed += stat._hashed;
_known += stat._known;
_new += stat._new;
_new_bytes += stat._new_bytes;
_deduped += stat._deduped;
_deduped_bytes += stat._deduped_bytes;
_deduped_young += stat._deduped_young;
_deduped_young_bytes += stat._deduped_young_bytes;
_deduped_old += stat._deduped_old;
_deduped_old_bytes += stat._deduped_old_bytes;
_idle += stat._idle;
_exec += stat._exec;
_block += stat._block;
_idle_elapsed += stat._idle_elapsed;
_exec_elapsed += stat._exec_elapsed;
_block_elapsed += stat._block_elapsed;
}
void G1StringDedupStat::print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
double total_deduped_bytes_percent = 0.0;
if (total_stat._new_bytes > 0) {
// Avoid division by zero
total_deduped_bytes_percent = (double)total_stat._deduped_bytes / (double)total_stat._new_bytes * 100.0;
}
st->date_stamp(PrintGCDateStamps);
st->stamp(PrintGCTimeStamps);
st->print_cr(
"[GC concurrent-string-deduplication, "
G1_STRDEDUP_BYTES_FORMAT_NS"->"G1_STRDEDUP_BYTES_FORMAT_NS"("G1_STRDEDUP_BYTES_FORMAT_NS"), avg "
G1_STRDEDUP_PERCENT_FORMAT_NS", "G1_STRDEDUP_TIME_FORMAT"]",
G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes),
G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes - last_stat._deduped_bytes),
G1_STRDEDUP_BYTES_PARAM(last_stat._deduped_bytes),
total_deduped_bytes_percent,
last_stat._exec_elapsed);
}
void G1StringDedupStat::print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total) {
double young_percent = 0.0;
double old_percent = 0.0;
double skipped_percent = 0.0;
double hashed_percent = 0.0;
double known_percent = 0.0;
double new_percent = 0.0;
double deduped_percent = 0.0;
double deduped_bytes_percent = 0.0;
double deduped_young_percent = 0.0;
double deduped_young_bytes_percent = 0.0;
double deduped_old_percent = 0.0;
double deduped_old_bytes_percent = 0.0;
if (stat._inspected > 0) {
// Avoid division by zero
skipped_percent = (double)stat._skipped / (double)stat._inspected * 100.0;
hashed_percent = (double)stat._hashed / (double)stat._inspected * 100.0;
known_percent = (double)stat._known / (double)stat._inspected * 100.0;
new_percent = (double)stat._new / (double)stat._inspected * 100.0;
}
if (stat._new > 0) {
// Avoid division by zero
deduped_percent = (double)stat._deduped / (double)stat._new * 100.0;
}
if (stat._deduped > 0) {
// Avoid division by zero
deduped_young_percent = (double)stat._deduped_young / (double)stat._deduped * 100.0;
deduped_old_percent = (double)stat._deduped_old / (double)stat._deduped * 100.0;
}
if (stat._new_bytes > 0) {
// Avoid division by zero
deduped_bytes_percent = (double)stat._deduped_bytes / (double)stat._new_bytes * 100.0;
}
if (stat._deduped_bytes > 0) {
// Avoid division by zero
deduped_young_bytes_percent = (double)stat._deduped_young_bytes / (double)stat._deduped_bytes * 100.0;
deduped_old_bytes_percent = (double)stat._deduped_old_bytes / (double)stat._deduped_bytes * 100.0;
}
if (total) {
st->print_cr(
" [Total Exec: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT", Idle: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT", Blocked: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT"]",
stat._exec, stat._exec_elapsed, stat._idle, stat._idle_elapsed, stat._block, stat._block_elapsed);
} else {
st->print_cr(
" [Last Exec: "G1_STRDEDUP_TIME_FORMAT", Idle: "G1_STRDEDUP_TIME_FORMAT", Blocked: "UINTX_FORMAT"/"G1_STRDEDUP_TIME_FORMAT"]",
stat._exec_elapsed, stat._idle_elapsed, stat._block, stat._block_elapsed);
}
st->print_cr(
" [Inspected: "G1_STRDEDUP_OBJECTS_FORMAT"]\n"
" [Skipped: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n"
" [Hashed: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n"
" [Known: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n"
" [New: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"]\n"
" [Deduplicated: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n"
" [Young: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]\n"
" [Old: "G1_STRDEDUP_OBJECTS_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT") "G1_STRDEDUP_BYTES_FORMAT"("G1_STRDEDUP_PERCENT_FORMAT")]",
stat._inspected,
stat._skipped, skipped_percent,
stat._hashed, hashed_percent,
stat._known, known_percent,
stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes),
stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent,
stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent,
stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent);
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP
#include "memory/allocation.hpp"
#include "runtime/os.hpp"
// Macros for GC log output formating
#define G1_STRDEDUP_OBJECTS_FORMAT UINTX_FORMAT_W(12)
#define G1_STRDEDUP_TIME_FORMAT "%1.7lf secs"
#define G1_STRDEDUP_PERCENT_FORMAT "%5.1lf%%"
#define G1_STRDEDUP_PERCENT_FORMAT_NS "%.1lf%%"
#define G1_STRDEDUP_BYTES_FORMAT "%8.1lf%s"
#define G1_STRDEDUP_BYTES_FORMAT_NS "%.1lf%s"
#define G1_STRDEDUP_BYTES_PARAM(bytes) byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes))
//
// Statistics gathered by the deduplication thread.
//
class G1StringDedupStat : public StackObj {
private:
// Counters
uintx _inspected;
uintx _skipped;
uintx _hashed;
uintx _known;
uintx _new;
uintx _new_bytes;
uintx _deduped;
uintx _deduped_bytes;
uintx _deduped_young;
uintx _deduped_young_bytes;
uintx _deduped_old;
uintx _deduped_old_bytes;
uintx _idle;
uintx _exec;
uintx _block;
// Time spent by the deduplication thread in different phases
double _start;
double _idle_elapsed;
double _exec_elapsed;
double _block_elapsed;
public:
G1StringDedupStat();
void inc_inspected() {
_inspected++;
}
void inc_skipped() {
_skipped++;
}
void inc_hashed() {
_hashed++;
}
void inc_known() {
_known++;
}
void inc_new(uintx bytes) {
_new++;
_new_bytes += bytes;
}
void inc_deduped_young(uintx bytes) {
_deduped++;
_deduped_bytes += bytes;
_deduped_young++;
_deduped_young_bytes += bytes;
}
void inc_deduped_old(uintx bytes) {
_deduped++;
_deduped_bytes += bytes;
_deduped_old++;
_deduped_old_bytes += bytes;
}
void mark_idle() {
_start = os::elapsedTime();
_idle++;
}
void mark_exec() {
double now = os::elapsedTime();
_idle_elapsed = now - _start;
_start = now;
_exec++;
}
void mark_block() {
double now = os::elapsedTime();
_exec_elapsed += now - _start;
_start = now;
_block++;
}
void mark_unblock() {
double now = os::elapsedTime();
_block_elapsed += now - _start;
_start = now;
}
void mark_done() {
double now = os::elapsedTime();
_exec_elapsed += now - _start;
}
void add(const G1StringDedupStat& stat);
static void print_summary(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
static void print_statistics(outputStream* st, const G1StringDedupStat& stat, bool total);
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPSTAT_HPP
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP
#include "gc_implementation/g1/g1StringDedupStat.hpp"
#include "runtime/mutexLocker.hpp"
class G1StringDedupEntryCache;
//
// Table entry in the deduplication hashtable. Points weakly to the
// character array. Can be chained in a linked list in case of hash
// collisions or when placed in a freelist in the entry cache.
//
class G1StringDedupEntry : public CHeapObj<mtGC> {
private:
G1StringDedupEntry* _next;
unsigned int _hash;
typeArrayOop _obj;
public:
G1StringDedupEntry() :
_next(NULL),
_hash(0),
_obj(NULL) {
}
G1StringDedupEntry* next() {
return _next;
}
G1StringDedupEntry** next_addr() {
return &_next;
}
void set_next(G1StringDedupEntry* next) {
_next = next;
}
unsigned int hash() {
return _hash;
}
void set_hash(unsigned int hash) {
_hash = hash;
}
typeArrayOop obj() {
return _obj;
}
typeArrayOop* obj_addr() {
return &_obj;
}
void set_obj(typeArrayOop obj) {
_obj = obj;
}
};
//
// The deduplication hashtable keeps track of all unique character arrays used
// by String objects. Each table entry weakly points to an character array, allowing
// otherwise unreachable character arrays to be declared dead and pruned from the
// table.
//
// The table is dynamically resized to accommodate the current number of table entries.
// The table has hash buckets with chains for hash collision. If the average chain
// length goes above or below given thresholds the table grows or shrinks accordingly.
//
// The table is also dynamically rehashed (using a new hash seed) if it becomes severely
// unbalanced, i.e., a hash chain is significantly longer than average.
//
// All access to the table is protected by the StringDedupTable_lock, except under
// safepoints in which case GC workers are allowed to access a table partitions they
// have claimed without first acquiring the lock. Note however, that this applies only
// the table partition (i.e. a range of elements in _buckets), not other parts of the
// table such as the _entries field, statistics counters, etc.
//
class G1StringDedupTable : public CHeapObj<mtGC> {
private:
// The currently active hashtable instance. Only modified when
// the table is resizes or rehashed.
static G1StringDedupTable* _table;
// Cache for reuse and fast alloc/free of table entries.
static G1StringDedupEntryCache* _entry_cache;
G1StringDedupEntry** _buckets;
size_t _size;
uintx _entries;
uintx _shrink_threshold;
uintx _grow_threshold;
bool _rehash_needed;
// The hash seed also dictates which hash function to use. A
// zero hash seed means we will use the Java compatible hash
// function (which doesn't use a seed), and a non-zero hash
// seed means we use the murmur3 hash function.
jint _hash_seed;
// Constants governing table resize/rehash/cache.
static const size_t _min_size;
static const size_t _max_size;
static const double _grow_load_factor;
static const double _shrink_load_factor;
static const uintx _rehash_multiple;
static const uintx _rehash_threshold;
static const double _max_cache_factor;
// Table statistics, only used for logging.
static uintx _entries_added;
static uintx _entries_removed;
static uintx _resize_count;
static uintx _rehash_count;
G1StringDedupTable(size_t size, jint hash_seed = 0);
~G1StringDedupTable();
// Returns the hash bucket at the given index.
G1StringDedupEntry** bucket(size_t index) {
return _buckets + index;
}
// Returns the hash bucket index for the given hash code.
size_t hash_to_index(unsigned int hash) {
return (size_t)hash & (_size - 1);
}
// Adds a new table entry to the given hash bucket.
void add(typeArrayOop value, unsigned int hash, G1StringDedupEntry** list);
// Removes the given table entry from the table.
void remove(G1StringDedupEntry** pentry, uint worker_id);
// Transfers a table entry from the current table to the destination table.
void transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest);
// Returns an existing character array in the given hash bucket, or NULL
// if no matching character array exists.
typeArrayOop lookup(typeArrayOop value, unsigned int hash,
G1StringDedupEntry** list, uintx &count);
// Returns an existing character array in the table, or inserts a new
// table entry if no matching character array exists.
typeArrayOop lookup_or_add_inner(typeArrayOop value, unsigned int hash);
// Thread safe lookup or add of table entry
static typeArrayOop lookup_or_add(typeArrayOop value, unsigned int hash) {
// Protect the table from concurrent access. Also note that this lock
// acts as a fence for _table, which could have been replaced by a new
// instance if the table was resized or rehashed.
MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
return _table->lookup_or_add_inner(value, hash);
}
// Returns true if the hashtable is currently using a Java compatible
// hash function.
static bool use_java_hash() {
return _table->_hash_seed == 0;
}
static bool equals(typeArrayOop value1, typeArrayOop value2);
// Computes the hash code for the given character array, using the
// currently active hash function and hash seed.
static unsigned int hash_code(typeArrayOop value);
static uintx unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl,
size_t partition_begin,
size_t partition_end,
uint worker_id);
public:
static void create();
// Deduplicates the given String object, or adds its backing
// character array to the deduplication hashtable.
static void deduplicate(oop java_string, G1StringDedupStat& stat);
// If a table resize is needed, returns a newly allocated empty
// hashtable of the proper size.
static G1StringDedupTable* prepare_resize();
// Installs a newly resized table as the currently active table
// and deletes the previously active table.
static void finish_resize(G1StringDedupTable* resized_table);
// If a table rehash is needed, returns a newly allocated empty
// hashtable and updates the hash seed.
static G1StringDedupTable* prepare_rehash();
// Transfers rehashed entries from the currently active table into
// the new table. Installs the new table as the currently active table
// and deletes the previously active table.
static void finish_rehash(G1StringDedupTable* rehashed_table);
// If the table entry cache has grown too large, trim it down according to policy
static void trim_entry_cache();
static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id);
static void print_statistics(outputStream* st);
static void verify();
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTABLE_HPP
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc_implementation/g1/g1Log.hpp"
#include "gc_implementation/g1/g1StringDedup.hpp"
#include "gc_implementation/g1/g1StringDedupTable.hpp"
#include "gc_implementation/g1/g1StringDedupThread.hpp"
#include "gc_implementation/g1/g1StringDedupQueue.hpp"
G1StringDedupThread* G1StringDedupThread::_thread = NULL;
G1StringDedupThread::G1StringDedupThread() :
ConcurrentGCThread() {
set_name("String Deduplication Thread");
create_and_start();
}
G1StringDedupThread::~G1StringDedupThread() {
ShouldNotReachHere();
}
void G1StringDedupThread::create() {
assert(G1StringDedup::is_enabled(), "String deduplication not enabled");
assert(_thread == NULL, "One string deduplication thread allowed");
_thread = new G1StringDedupThread();
}
G1StringDedupThread* G1StringDedupThread::thread() {
assert(G1StringDedup::is_enabled(), "String deduplication not enabled");
assert(_thread != NULL, "String deduplication thread not created");
return _thread;
}
void G1StringDedupThread::print_on(outputStream* st) const {
st->print("\"%s\" ", name());
Thread::print_on(st);
st->cr();
}
void G1StringDedupThread::run() {
G1StringDedupStat total_stat;
initialize_in_thread();
wait_for_universe_init();
// Main loop
for (;;) {
G1StringDedupStat stat;
stat.mark_idle();
// Wait for the queue to become non-empty
G1StringDedupQueue::wait();
// Include this thread in safepoints
stsJoin();
stat.mark_exec();
// Process the queue
for (;;) {
oop java_string = G1StringDedupQueue::pop();
if (java_string == NULL) {
break;
}
G1StringDedupTable::deduplicate(java_string, stat);
// Safepoint this thread if needed
if (stsShouldYield()) {
stat.mark_block();
stsYield(NULL);
stat.mark_unblock();
}
}
G1StringDedupTable::trim_entry_cache();
stat.mark_done();
// Print statistics
total_stat.add(stat);
print(gclog_or_tty, stat, total_stat);
// Exclude this thread from safepoints
stsLeave();
}
ShouldNotReachHere();
}
void G1StringDedupThread::print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
if (G1Log::fine() || PrintStringDeduplicationStatistics) {
G1StringDedupStat::print_summary(st, last_stat, total_stat);
if (PrintStringDeduplicationStatistics) {
G1StringDedupStat::print_statistics(st, last_stat, false);
G1StringDedupStat::print_statistics(st, total_stat, true);
G1StringDedupTable::print_statistics(st);
G1StringDedupQueue::print_statistics(st);
}
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP
#include "gc_implementation/g1/g1StringDedupStat.hpp"
#include "gc_implementation/shared/concurrentGCThread.hpp"
//
// The deduplication thread is where the actual deduplication occurs. It waits for
// deduplication candidates to appear on the deduplication queue, removes them from
// the queue and tries to deduplicate them. It uses the deduplication hashtable to
// find identical, already existing, character arrays on the heap. The thread runs
// concurrently with the Java application but participates in safepoints to allow
// the GC to adjust and unlink oops from the deduplication queue and table.
//
class G1StringDedupThread: public ConcurrentGCThread {
private:
static G1StringDedupThread* _thread;
G1StringDedupThread();
~G1StringDedupThread();
void print(outputStream* st, const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
public:
static void create();
static G1StringDedupThread* thread();
virtual void run();
virtual void print_on(outputStream* st) const;
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1STRINGDEDUPTHREAD_HPP
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -30,10 +30,18 @@
#include "utilities/stack.inline.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/g1StringDedup.hpp"
#include "gc_implementation/parallelScavenge/psParallelCompact.hpp"
#endif // INCLUDE_ALL_GCS
inline void MarkSweep::mark_object(oop obj) {
#if INCLUDE_ALL_GCS
if (G1StringDedup::is_enabled()) {
// We must enqueue the object before it is marked
// as we otherwise can't read the object's age.
G1StringDedup::enqueue_from_mark(obj);
}
#endif
// some marks may contain information we need to preserve so we store them away
// and overwrite the mark. We'll restore it at the end of markSweep.
markOop mark = obj->mark();
......
......@@ -2217,6 +2217,8 @@ bool Arguments::check_vm_args_consistency() {
"G1ConcRSHotCardLimit");
status = status && verify_interval(G1ConcRSLogCacheSize, 0, 31,
"G1ConcRSLogCacheSize");
status = status && verify_interval(StringDeduplicationAgeThreshold, 1, markOopDesc::max_age,
"StringDeduplicationAgeThreshold");
}
if (UseConcMarkSweepGC) {
status = status && verify_min_value(CMSOldPLABNumRefills, 1, "CMSOldPLABNumRefills");
......
......@@ -3812,6 +3812,22 @@ class CommandLineFlags {
experimental(uintx, SymbolTableSize, defaultSymbolTableSize, \
"Number of buckets in the JVM internal Symbol table") \
\
product(bool, UseStringDeduplication, false, \
"Use string deduplication") \
\
product(bool, PrintStringDeduplicationStatistics, false, \
"Print string deduplication statistics") \
\
product(uintx, StringDeduplicationAgeThreshold, 3, \
"A string must reach this age (or be promoted to an old region) " \
"to be considered for deduplication") \
\
diagnostic(bool, StringDeduplicationResizeALot, false, \
"Force table resize every time the table is scanned") \
\
diagnostic(bool, StringDeduplicationRehashALot, false, \
"Force table rehash every time the table is scanned") \
\
develop(bool, TraceDefaultMethods, false, \
"Trace the default method processing steps") \
\
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -58,6 +58,8 @@ Mutex* SignatureHandlerLibrary_lock = NULL;
Mutex* VtableStubs_lock = NULL;
Mutex* SymbolTable_lock = NULL;
Mutex* StringTable_lock = NULL;
Monitor* StringDedupQueue_lock = NULL;
Mutex* StringDedupTable_lock = NULL;
Mutex* CodeCache_lock = NULL;
Mutex* MethodData_lock = NULL;
Mutex* RetData_lock = NULL;
......@@ -196,6 +198,9 @@ void mutex_init() {
def(MMUTracker_lock , Mutex , leaf , true );
def(HotCardCache_lock , Mutex , special , true );
def(EvacFailureStack_lock , Mutex , nonleaf , true );
def(StringDedupQueue_lock , Monitor, leaf, true );
def(StringDedupTable_lock , Mutex , leaf, true );
}
def(ParGCRareEvent_lock , Mutex , leaf , true );
def(DerivedPointerTableGC_lock , Mutex, leaf, true );
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -63,6 +63,8 @@ extern Mutex* SignatureHandlerLibrary_lock; // a lock on the SignatureHandl
extern Mutex* VtableStubs_lock; // a lock on the VtableStubs
extern Mutex* SymbolTable_lock; // a lock on the symbol table
extern Mutex* StringTable_lock; // a lock on the interned string table
extern Monitor* StringDedupQueue_lock; // a lock on the string deduplication queue
extern Mutex* StringDedupTable_lock; // a lock on the string deduplication table
extern Mutex* CodeCache_lock; // a lock on the CodeCache, rank is special, use MutexLockerEx
extern Mutex* MethodData_lock; // a lock on installation of method data
extern Mutex* RetData_lock; // a lock on installation of RetData inside method data
......
......@@ -49,11 +49,13 @@ public class TestGCLogMessages {
output.shouldNotContain("[Redirty Cards");
output.shouldNotContain("[Code Root Purge");
output.shouldNotContain("[String Dedup Fixup");
output.shouldNotContain("[Young Free CSet");
output.shouldNotContain("[Non-Young Free CSet");
output.shouldHaveExitValue(0);
pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
"-XX:+UseStringDeduplication",
"-Xmx10M",
"-XX:+PrintGCDetails",
GCTest.class.getName());
......@@ -62,11 +64,13 @@ public class TestGCLogMessages {
output.shouldContain("[Redirty Cards");
output.shouldContain("[Code Root Purge");
output.shouldContain("[String Dedup Fixup");
output.shouldNotContain("[Young Free CSet");
output.shouldNotContain("[Non-Young Free CSet");
output.shouldHaveExitValue(0);
pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
"-XX:+UseStringDeduplication",
"-Xmx10M",
"-XX:+PrintGCDetails",
"-XX:+UnlockExperimentalVMOptions",
......@@ -77,6 +81,7 @@ public class TestGCLogMessages {
output.shouldContain("[Redirty Cards");
output.shouldContain("[Code Root Purge");
output.shouldContain("[String Dedup Fixup");
output.shouldContain("[Young Free CSet");
output.shouldContain("[Non-Young Free CSet");
......
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestStringDeduplicationAgeThreshold
* @summary Test string deduplication age threshold
* @bug 8029075
* @key gc
* @library /testlibrary
*/
public class TestStringDeduplicationAgeThreshold {
public static void main(String[] args) throws Exception {
TestStringDeduplicationTools.testAgeThreshold();
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestStringDeduplicationFullGC
* @summary Test string deduplication during full GC
* @bug 8029075
* @key gc
* @library /testlibrary
*/
public class TestStringDeduplicationFullGC {
public static void main(String[] args) throws Exception {
TestStringDeduplicationTools.testFullGC();
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestStringDeduplicationInterned
* @summary Test string deduplication of interned strings
* @bug 8029075
* @key gc
* @library /testlibrary
*/
public class TestStringDeduplicationInterned {
public static void main(String[] args) throws Exception {
TestStringDeduplicationTools.testInterned();
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestStringDeduplicationMemoryUsage
* @summary Test string deduplication memory usage
* @bug 8029075
* @key gc
* @library /testlibrary
*/
public class TestStringDeduplicationMemoryUsage {
public static void main(String[] args) throws Exception {
TestStringDeduplicationTools.testMemoryUsage();
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestStringDeduplicationPrintOptions
* @summary Test string deduplication print options
* @bug 8029075
* @key gc
* @library /testlibrary
*/
public class TestStringDeduplicationPrintOptions {
public static void main(String[] args) throws Exception {
TestStringDeduplicationTools.testPrintOptions();
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestStringDeduplicationTableRehash
* @summary Test string deduplication table rehash
* @bug 8029075
* @key gc
* @library /testlibrary
*/
public class TestStringDeduplicationTableRehash {
public static void main(String[] args) throws Exception {
TestStringDeduplicationTools.testTableRehash();
}
}
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestStringDeduplicationTableResize
* @summary Test string deduplication table resize
* @bug 8029075
* @key gc
* @library /testlibrary
*/
public class TestStringDeduplicationTableResize {
public static void main(String[] args) throws Exception {
TestStringDeduplicationTools.testTableResize();
}
}
此差异已折叠。
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestStringDeduplicationYoungGC
* @summary Test string deduplication during young GC
* @bug 8029075
* @key gc
* @library /testlibrary
*/
public class TestStringDeduplicationYoungGC {
public static void main(String[] args) throws Exception {
TestStringDeduplicationTools.testYoungGC();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册