提交 16670578 编写于 作者: V vkempik

8158871: Long response times with G1 and StringDeduplication

Reviewed-by: pliden, tschatzl
上级 e1b27304
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2016, 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
......@@ -28,22 +28,23 @@
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
#include "gc_implementation/g1/g1StringDedupTable.hpp"
#include "gc_implementation/shared/concurrentGCThread.hpp"
#include "memory/gcLocker.hpp"
#include "memory/padded.inline.hpp"
#include "oops/typeArrayOop.hpp"
#include "runtime/mutexLocker.hpp"
//
// Freelist in the deduplication table entry cache. Links table
// List of deduplication table entries. Links table
// entries together using their _next fields.
//
class G1StringDedupEntryFreeList : public CHeapObj<mtGC> {
class G1StringDedupEntryList : public CHeapObj<mtGC> {
private:
G1StringDedupEntry* _list;
size_t _length;
public:
G1StringDedupEntryFreeList() :
G1StringDedupEntryList() :
_list(NULL),
_length(0) {
}
......@@ -63,6 +64,12 @@ public:
return entry;
}
G1StringDedupEntry* remove_all() {
G1StringDedupEntry* list = _list;
_list = NULL;
return list;
}
size_t length() {
return _length;
}
......@@ -84,43 +91,53 @@ public:
//
class G1StringDedupEntryCache : public CHeapObj<mtGC> {
private:
// One freelist per GC worker to allow lock less freeing of
// entries while doing a parallel scan of the table. Using
// PaddedEnd to avoid false sharing.
PaddedEnd<G1StringDedupEntryFreeList>* _lists;
size_t _nlists;
// One cache/overflow list per GC worker to allow lock less freeing of
// entries while doing a parallel scan of the table. Using PaddedEnd to
// avoid false sharing.
size_t _nlists;
size_t _max_list_length;
PaddedEnd<G1StringDedupEntryList>* _cached;
PaddedEnd<G1StringDedupEntryList>* _overflowed;
public:
G1StringDedupEntryCache();
G1StringDedupEntryCache(size_t max_size);
~G1StringDedupEntryCache();
// Get a table entry from the cache freelist, or allocate a new
// entry if the cache is empty.
// Set max number of table entries to cache.
void set_max_size(size_t max_size);
// Get a table entry from the cache, or allocate a new entry if the cache is empty.
G1StringDedupEntry* alloc();
// Insert a table entry into the cache freelist.
// Insert a table entry into the cache.
void free(G1StringDedupEntry* entry, uint worker_id);
// Returns current number of entries in the cache.
size_t size();
// If the cache has grown above the given max size, trim it down
// and deallocate the memory occupied by trimmed of entries.
void trim(size_t max_size);
// Deletes overflowed entries.
void delete_overflowed();
};
G1StringDedupEntryCache::G1StringDedupEntryCache() {
_nlists = MAX2(ParallelGCThreads, (size_t)1);
_lists = PaddedArray<G1StringDedupEntryFreeList, mtGC>::create_unfreeable((uint)_nlists);
G1StringDedupEntryCache::G1StringDedupEntryCache(size_t max_size) :
_nlists(MAX2(ParallelGCThreads, (size_t)1)),
_max_list_length(0),
_cached(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)),
_overflowed(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)) {
set_max_size(max_size);
}
G1StringDedupEntryCache::~G1StringDedupEntryCache() {
ShouldNotReachHere();
}
void G1StringDedupEntryCache::set_max_size(size_t size) {
_max_list_length = size / _nlists;
}
G1StringDedupEntry* G1StringDedupEntryCache::alloc() {
for (size_t i = 0; i < _nlists; i++) {
G1StringDedupEntry* entry = _lists[i].remove();
G1StringDedupEntry* entry = _cached[i].remove();
if (entry != NULL) {
return entry;
}
......@@ -131,31 +148,55 @@ G1StringDedupEntry* G1StringDedupEntryCache::alloc() {
void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) {
assert(entry->obj() != NULL, "Double free");
assert(worker_id < _nlists, "Invalid worker id");
entry->set_obj(NULL);
entry->set_hash(0);
_lists[worker_id].add(entry);
if (_cached[worker_id].length() < _max_list_length) {
// Cache is not full
_cached[worker_id].add(entry);
} else {
// Cache is full, add to overflow list for later deletion
_overflowed[worker_id].add(entry);
}
}
size_t G1StringDedupEntryCache::size() {
size_t size = 0;
for (size_t i = 0; i < _nlists; i++) {
size += _lists[i].length();
size += _cached[i].length();
}
return size;
}
void G1StringDedupEntryCache::trim(size_t max_size) {
size_t cache_size = 0;
void G1StringDedupEntryCache::delete_overflowed() {
double start = os::elapsedTime();
uintx count = 0;
for (size_t i = 0; i < _nlists; i++) {
G1StringDedupEntryFreeList* list = &_lists[i];
cache_size += list->length();
while (cache_size > max_size) {
G1StringDedupEntry* entry = list->remove();
assert(entry != NULL, "Should not be null");
cache_size--;
G1StringDedupEntry* entry;
{
// The overflow list can be modified during safepoints, therefore
// we temporarily join the suspendible thread set while removing
// all entries from the list.
SuspendibleThreadSetJoiner sts_join;
entry = _overflowed[i].remove_all();
}
// Delete all entries
while (entry != NULL) {
G1StringDedupEntry* next = entry->next();
delete entry;
entry = next;
count++;
}
}
double end = os::elapsedTime();
if (PrintStringDeduplicationStatistics) {
gclog_or_tty->print_cr("[GC concurrent-string-deduplication, deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT "]", count, end - start);
}
}
G1StringDedupTable* G1StringDedupTable::_table = NULL;
......@@ -192,7 +233,7 @@ G1StringDedupTable::~G1StringDedupTable() {
void G1StringDedupTable::create() {
assert(_table == NULL, "One string deduplication table allowed");
_entry_cache = new G1StringDedupEntryCache();
_entry_cache = new G1StringDedupEntryCache((size_t)(_min_size * _max_cache_factor));
_table = new G1StringDedupTable(_min_size);
}
......@@ -375,6 +416,9 @@ G1StringDedupTable* G1StringDedupTable::prepare_resize() {
// Update statistics
_resize_count++;
// Update max cache size
_entry_cache->set_max_size((size_t)(size * _max_cache_factor));
// Allocate the new table. The new table will be populated by workers
// calling unlink_or_oops_do() and finally installed by finish_resize().
return new G1StringDedupTable(size, _table->_hash_seed);
......@@ -427,7 +471,7 @@ void G1StringDedupTable::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* c
removed += unlink_or_oops_do(cl, table_half + partition_begin, table_half + partition_end, worker_id);
}
// Delayed update avoid contention on the table lock
// Delayed update to avoid contention on the table lock
if (removed > 0) {
MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
_table->_entries -= removed;
......@@ -545,10 +589,8 @@ void G1StringDedupTable::verify() {
}
}
void G1StringDedupTable::trim_entry_cache() {
MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag);
size_t max_cache_size = (size_t)(_table->_size * _max_cache_factor);
_entry_cache->trim(max_cache_size);
void G1StringDedupTable::clean_entry_cache() {
_entry_cache->delete_overflowed();
}
void G1StringDedupTable::print_statistics(outputStream* st) {
......
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2016, 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
......@@ -218,8 +218,8 @@ public:
// 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();
// If the table entry cache has grown too large, delete overflowed entries.
static void clean_entry_cache();
static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id);
......
......@@ -100,14 +100,14 @@ void G1StringDedupThread::run() {
}
}
G1StringDedupTable::trim_entry_cache();
stat.mark_done();
// Print statistics
total_stat.add(stat);
print(gclog_or_tty, stat, total_stat);
}
G1StringDedupTable::clean_entry_cache();
}
terminate();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册