aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm
diff options
context:
space:
mode:
authorasaha <none@none>2014-04-09 12:23:29 -0700
committerasaha <none@none>2014-04-09 12:23:29 -0700
commit4c961dda820faf4296b67c386f8c65f8bc3bd3af (patch)
treeb98d79cf0fcb1fa966ee9fc89a4c09b1853d114d /src/share/vm
parente4fee34d9dfb9c9f6d3662289e1140e6ebe54324 (diff)
parentc2e055adca4025d403b5773340ef0f34da26d529 (diff)
Merge
Diffstat (limited to 'src/share/vm')
-rw-r--r--src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp1
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp23
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp151
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp143
-rw-r--r--src/share/vm/gc_implementation/g1/sparsePRT.hpp2
-rw-r--r--src/share/vm/prims/jni.cpp2
-rw-r--r--src/share/vm/runtime/arguments.cpp18
-rw-r--r--src/share/vm/runtime/globals.cpp2
-rw-r--r--src/share/vm/runtime/globals.hpp6
-rw-r--r--src/share/vm/runtime/safepoint.cpp2
-rw-r--r--src/share/vm/runtime/vm_operations.hpp12
-rw-r--r--src/share/vm/services/diagnosticCommand.cpp9
-rw-r--r--src/share/vm/services/diagnosticCommand.hpp17
-rw-r--r--src/share/vm/utilities/ostream.cpp28
-rw-r--r--src/share/vm/utilities/ostream.hpp11
15 files changed, 265 insertions, 162 deletions
diff --git a/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp b/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp
index 7bdb98f16..ddebcf530 100644
--- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp
+++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "gc_implementation/g1/dirtyCardQueue.hpp"
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/heapRegionRemSet.hpp"
#include "runtime/atomic.hpp"
#include "runtime/mutexLocker.hpp"
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
index c13eec974..f73eab90b 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
@@ -3547,6 +3547,29 @@ public:
}
};
+bool G1CollectedHeap::is_obj_dead_cond(const oop obj,
+ const HeapRegion* hr,
+ const VerifyOption vo) const {
+ switch (vo) {
+ case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj, hr);
+ case VerifyOption_G1UseNextMarking: return is_obj_ill(obj, hr);
+ case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked();
+ default: ShouldNotReachHere();
+ }
+ return false; // keep some compilers happy
+}
+
+bool G1CollectedHeap::is_obj_dead_cond(const oop obj,
+ const VerifyOption vo) const {
+ switch (vo) {
+ case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj);
+ case VerifyOption_G1UseNextMarking: return is_obj_ill(obj);
+ case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked();
+ default: ShouldNotReachHere();
+ }
+ return false; // keep some compilers happy
+}
+
void G1CollectedHeap::print_on(outputStream* st) const {
st->print(" %-20s", "garbage-first heap");
st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
index d50897d35..a18436eec 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
@@ -706,19 +706,7 @@ public:
// This is a fast test on whether a reference points into the
// collection set or not. Assume that the reference
// points into the heap.
- bool in_cset_fast_test(oop obj) {
- assert(_in_cset_fast_test != NULL, "sanity");
- assert(_g1_committed.contains((HeapWord*) obj), err_msg("Given reference outside of heap, is "PTR_FORMAT, (HeapWord*)obj));
- // no need to subtract the bottom of the heap from obj,
- // _in_cset_fast_test is biased
- uintx index = cast_from_oop<uintx>(obj) >> HeapRegion::LogOfHRGrainBytes;
- bool ret = _in_cset_fast_test[index];
- // let's make sure the result is consistent with what the slower
- // test returns
- assert( ret || !obj_in_cs(obj), "sanity");
- assert(!ret || obj_in_cs(obj), "sanity");
- return ret;
- }
+ inline bool in_cset_fast_test(oop obj);
void clear_cset_fast_test() {
assert(_in_cset_fast_test_base != NULL, "sanity");
@@ -1264,9 +1252,7 @@ public:
}
}
- void old_set_remove(HeapRegion* hr) {
- _old_set.remove(hr);
- }
+ inline void old_set_remove(HeapRegion* hr);
size_t non_young_capacity_bytes() {
return _old_set.total_capacity_bytes() + _humongous_set.total_capacity_bytes();
@@ -1357,7 +1343,7 @@ public:
void heap_region_iterate(HeapRegionClosure* blk) const;
// Return the region with the given index. It assumes the index is valid.
- HeapRegion* region_at(uint index) const { return _hrs.at(index); }
+ inline HeapRegion* region_at(uint index) const;
// Divide the heap region sequence into "chunks" of some size (the number
// of regions divided by the number of parallel threads times some
@@ -1486,10 +1472,7 @@ public:
return true;
}
- bool is_in_young(const oop obj) {
- HeapRegion* hr = heap_region_containing(obj);
- return hr != NULL && hr->is_young();
- }
+ inline bool is_in_young(const oop obj);
#ifdef ASSERT
virtual bool is_in_partial_collection(const void* p);
@@ -1502,9 +1485,7 @@ public:
// pre-value that needs to be remembered; for the remembered-set
// update logging post-barrier, we don't maintain remembered set
// information for young gen objects.
- virtual bool can_elide_initializing_store_barrier(oop new_obj) {
- return is_in_young(new_obj);
- }
+ virtual inline bool can_elide_initializing_store_barrier(oop new_obj);
// Returns "true" iff the given word_size is "very large".
static bool isHumongous(size_t word_size) {
@@ -1598,23 +1579,9 @@ public:
// Added if it is NULL it isn't dead.
- bool is_obj_dead(const oop obj) const {
- const HeapRegion* hr = heap_region_containing(obj);
- if (hr == NULL) {
- if (obj == NULL) return false;
- else return true;
- }
- else return is_obj_dead(obj, hr);
- }
+ inline bool is_obj_dead(const oop obj) const;
- bool is_obj_ill(const oop obj) const {
- const HeapRegion* hr = heap_region_containing(obj);
- if (hr == NULL) {
- if (obj == NULL) return false;
- else return true;
- }
- else return is_obj_ill(obj, hr);
- }
+ inline bool is_obj_ill(const oop obj) const;
bool allocated_since_marking(oop obj, HeapRegion* hr, VerifyOption vo);
HeapWord* top_at_mark_start(HeapRegion* hr, VerifyOption vo);
@@ -1708,26 +1675,10 @@ public:
bool is_obj_dead_cond(const oop obj,
const HeapRegion* hr,
- const VerifyOption vo) const {
- switch (vo) {
- case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj, hr);
- case VerifyOption_G1UseNextMarking: return is_obj_ill(obj, hr);
- case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked();
- default: ShouldNotReachHere();
- }
- return false; // keep some compilers happy
- }
+ const VerifyOption vo) const;
bool is_obj_dead_cond(const oop obj,
- const VerifyOption vo) const {
- switch (vo) {
- case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj);
- case VerifyOption_G1UseNextMarking: return is_obj_ill(obj);
- case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked();
- default: ShouldNotReachHere();
- }
- return false; // keep some compilers happy
- }
+ const VerifyOption vo) const;
// Printing
@@ -1821,11 +1772,7 @@ protected:
DirtyCardQueue& dirty_card_queue() { return _dcq; }
G1SATBCardTableModRefBS* ctbs() { return _ct_bs; }
- template <class T> void immediate_rs_update(HeapRegion* from, T* p, int tid) {
- if (!from->is_survivor()) {
- _g1_rem->par_write_ref(from, p, tid);
- }
- }
+ template <class T> inline void immediate_rs_update(HeapRegion* from, T* p, int tid);
template <class T> void deferred_rs_update(HeapRegion* from, T* p, int tid) {
// If the new value of the field points to the same region or
@@ -1867,13 +1814,7 @@ public:
refs()->push(ref);
}
- template <class T> void update_rs(HeapRegion* from, T* p, int tid) {
- if (G1DeferredRSUpdate) {
- deferred_rs_update(from, p, tid);
- } else {
- immediate_rs_update(from, p, tid);
- }
- }
+ template <class T> inline void update_rs(HeapRegion* from, T* p, int tid);
HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz) {
HeapWord* obj = NULL;
@@ -1997,54 +1938,7 @@ private:
return cast_to_oop((intptr_t)ref & ~G1_PARTIAL_ARRAY_MASK);
}
- void do_oop_partial_array(oop* p) {
- assert(has_partial_array_mask(p), "invariant");
- oop from_obj = clear_partial_array_mask(p);
-
- assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap.");
- assert(from_obj->is_objArray(), "must be obj array");
- objArrayOop from_obj_array = objArrayOop(from_obj);
- // The from-space object contains the real length.
- int length = from_obj_array->length();
-
- assert(from_obj->is_forwarded(), "must be forwarded");
- oop to_obj = from_obj->forwardee();
- assert(from_obj != to_obj, "should not be chunking self-forwarded objects");
- objArrayOop to_obj_array = objArrayOop(to_obj);
- // We keep track of the next start index in the length field of the
- // to-space object.
- int next_index = to_obj_array->length();
- assert(0 <= next_index && next_index < length,
- err_msg("invariant, next index: %d, length: %d", next_index, length));
-
- int start = next_index;
- int end = length;
- int remainder = end - start;
- // We'll try not to push a range that's smaller than ParGCArrayScanChunk.
- if (remainder > 2 * ParGCArrayScanChunk) {
- end = start + ParGCArrayScanChunk;
- to_obj_array->set_length(end);
- // Push the remainder before we process the range in case another
- // worker has run out of things to do and can steal it.
- oop* from_obj_p = set_partial_array_mask(from_obj);
- push_on_queue(from_obj_p);
- } else {
- assert(length == end, "sanity");
- // We'll process the final range for this object. Restore the length
- // so that the heap remains parsable in case of evacuation failure.
- to_obj_array->set_length(end);
- }
- _scanner.set_region(_g1h->heap_region_containing_raw(to_obj));
- // Process indexes [start,end). It will also process the header
- // along with the first chunk (i.e., the chunk with start == 0).
- // Note that at this point the length field of to_obj_array is not
- // correct given that we are using it to keep track of the next
- // start index. oop_iterate_range() (thankfully!) ignores the length
- // field and only relies on the start / end parameters. It does
- // however return the size of the object which will be incorrect. So
- // we have to ignore it even if we wanted to use it.
- to_obj_array->oop_iterate_range(&_scanner, start, end);
- }
+ inline void do_oop_partial_array(oop* p);
// This method is applied to the fields of the objects that have just been copied.
template <class T> void do_oop_evac(T* p, HeapRegion* from) {
@@ -2074,26 +1968,9 @@ public:
oop copy_to_survivor_space(oop const obj);
- template <class T> void deal_with_reference(T* ref_to_scan) {
- if (!has_partial_array_mask(ref_to_scan)) {
- // Note: we can use "raw" versions of "region_containing" because
- // "obj_to_scan" is definitely in the heap, and is not in a
- // humongous region.
- HeapRegion* r = _g1h->heap_region_containing_raw(ref_to_scan);
- do_oop_evac(ref_to_scan, r);
- } else {
- do_oop_partial_array((oop*)ref_to_scan);
- }
- }
+ template <class T> inline void deal_with_reference(T* ref_to_scan);
- void deal_with_reference(StarTask ref) {
- assert(verify_task(ref), "sanity");
- if (ref.is_narrow()) {
- deal_with_reference((narrowOop*)ref);
- } else {
- deal_with_reference((oop*)ref);
- }
- }
+ inline void deal_with_reference(StarTask ref);
public:
void trim_queue();
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp
index 91289d649..e3b8fd061 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp
@@ -29,6 +29,7 @@
#include "gc_implementation/g1/g1CollectedHeap.hpp"
#include "gc_implementation/g1/g1AllocRegion.inline.hpp"
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
+#include "gc_implementation/g1/g1RemSet.inline.hpp"
#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
#include "gc_implementation/g1/heapRegionSet.inline.hpp"
#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
@@ -36,6 +37,9 @@
// Inline functions for G1CollectedHeap
+// Return the region with the given index. It assumes the index is valid.
+inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrs.at(index); }
+
template <class T>
inline HeapRegion*
G1CollectedHeap::heap_region_containing(const T addr) const {
@@ -55,6 +59,10 @@ G1CollectedHeap::heap_region_containing_raw(const T addr) const {
return res;
}
+inline void G1CollectedHeap::old_set_remove(HeapRegion* hr) {
+ _old_set.remove(hr);
+}
+
inline bool G1CollectedHeap::obj_in_cs(oop obj) {
HeapRegion* r = _hrs.addr_to_region((HeapWord*) obj);
return r != NULL && r->in_collection_set();
@@ -151,6 +159,24 @@ inline bool G1CollectedHeap::isMarkedNext(oop obj) const {
return _cm->nextMarkBitMap()->isMarked((HeapWord *)obj);
}
+
+// This is a fast test on whether a reference points into the
+// collection set or not. Assume that the reference
+// points into the heap.
+inline bool G1CollectedHeap::in_cset_fast_test(oop obj) {
+ assert(_in_cset_fast_test != NULL, "sanity");
+ assert(_g1_committed.contains((HeapWord*) obj), err_msg("Given reference outside of heap, is "PTR_FORMAT, (HeapWord*)obj));
+ // no need to subtract the bottom of the heap from obj,
+ // _in_cset_fast_test is biased
+ uintx index = cast_from_oop<uintx>(obj) >> HeapRegion::LogOfHRGrainBytes;
+ bool ret = _in_cset_fast_test[index];
+ // let's make sure the result is consistent with what the slower
+ // test returns
+ assert( ret || !obj_in_cs(obj), "sanity");
+ assert(!ret || obj_in_cs(obj), "sanity");
+ return ret;
+}
+
#ifndef PRODUCT
// Support for G1EvacuationFailureALot
@@ -224,4 +250,121 @@ inline void G1CollectedHeap::reset_evacuation_should_fail() {
}
#endif // #ifndef PRODUCT
+inline bool G1CollectedHeap::is_in_young(const oop obj) {
+ HeapRegion* hr = heap_region_containing(obj);
+ return hr != NULL && hr->is_young();
+}
+
+// We don't need barriers for initializing stores to objects
+// in the young gen: for the SATB pre-barrier, there is no
+// pre-value that needs to be remembered; for the remembered-set
+// update logging post-barrier, we don't maintain remembered set
+// information for young gen objects.
+inline bool G1CollectedHeap::can_elide_initializing_store_barrier(oop new_obj) {
+ return is_in_young(new_obj);
+}
+
+inline bool G1CollectedHeap::is_obj_dead(const oop obj) const {
+ const HeapRegion* hr = heap_region_containing(obj);
+ if (hr == NULL) {
+ if (obj == NULL) return false;
+ else return true;
+ }
+ else return is_obj_dead(obj, hr);
+}
+
+inline bool G1CollectedHeap::is_obj_ill(const oop obj) const {
+ const HeapRegion* hr = heap_region_containing(obj);
+ if (hr == NULL) {
+ if (obj == NULL) return false;
+ else return true;
+ }
+ else return is_obj_ill(obj, hr);
+}
+
+template <class T> inline void G1ParScanThreadState::immediate_rs_update(HeapRegion* from, T* p, int tid) {
+ if (!from->is_survivor()) {
+ _g1_rem->par_write_ref(from, p, tid);
+ }
+}
+
+template <class T> void G1ParScanThreadState::update_rs(HeapRegion* from, T* p, int tid) {
+ if (G1DeferredRSUpdate) {
+ deferred_rs_update(from, p, tid);
+ } else {
+ immediate_rs_update(from, p, tid);
+ }
+}
+
+
+inline void G1ParScanThreadState::do_oop_partial_array(oop* p) {
+ assert(has_partial_array_mask(p), "invariant");
+ oop from_obj = clear_partial_array_mask(p);
+
+ assert(Universe::heap()->is_in_reserved(from_obj), "must be in heap.");
+ assert(from_obj->is_objArray(), "must be obj array");
+ objArrayOop from_obj_array = objArrayOop(from_obj);
+ // The from-space object contains the real length.
+ int length = from_obj_array->length();
+
+ assert(from_obj->is_forwarded(), "must be forwarded");
+ oop to_obj = from_obj->forwardee();
+ assert(from_obj != to_obj, "should not be chunking self-forwarded objects");
+ objArrayOop to_obj_array = objArrayOop(to_obj);
+ // We keep track of the next start index in the length field of the
+ // to-space object.
+ int next_index = to_obj_array->length();
+ assert(0 <= next_index && next_index < length,
+ err_msg("invariant, next index: %d, length: %d", next_index, length));
+
+ int start = next_index;
+ int end = length;
+ int remainder = end - start;
+ // We'll try not to push a range that's smaller than ParGCArrayScanChunk.
+ if (remainder > 2 * ParGCArrayScanChunk) {
+ end = start + ParGCArrayScanChunk;
+ to_obj_array->set_length(end);
+ // Push the remainder before we process the range in case another
+ // worker has run out of things to do and can steal it.
+ oop* from_obj_p = set_partial_array_mask(from_obj);
+ push_on_queue(from_obj_p);
+ } else {
+ assert(length == end, "sanity");
+ // We'll process the final range for this object. Restore the length
+ // so that the heap remains parsable in case of evacuation failure.
+ to_obj_array->set_length(end);
+ }
+ _scanner.set_region(_g1h->heap_region_containing_raw(to_obj));
+ // Process indexes [start,end). It will also process the header
+ // along with the first chunk (i.e., the chunk with start == 0).
+ // Note that at this point the length field of to_obj_array is not
+ // correct given that we are using it to keep track of the next
+ // start index. oop_iterate_range() (thankfully!) ignores the length
+ // field and only relies on the start / end parameters. It does
+ // however return the size of the object which will be incorrect. So
+ // we have to ignore it even if we wanted to use it.
+ to_obj_array->oop_iterate_range(&_scanner, start, end);
+}
+
+template <class T> inline void G1ParScanThreadState::deal_with_reference(T* ref_to_scan) {
+ if (!has_partial_array_mask(ref_to_scan)) {
+ // Note: we can use "raw" versions of "region_containing" because
+ // "obj_to_scan" is definitely in the heap, and is not in a
+ // humongous region.
+ HeapRegion* r = _g1h->heap_region_containing_raw(ref_to_scan);
+ do_oop_evac(ref_to_scan, r);
+ } else {
+ do_oop_partial_array((oop*)ref_to_scan);
+ }
+}
+
+inline void G1ParScanThreadState::deal_with_reference(StarTask ref) {
+ assert(verify_task(ref), "sanity");
+ if (ref.is_narrow()) {
+ deal_with_reference((narrowOop*)ref);
+ } else {
+ deal_with_reference((oop*)ref);
+ }
+}
+
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTEDHEAP_INLINE_HPP
diff --git a/src/share/vm/gc_implementation/g1/sparsePRT.hpp b/src/share/vm/gc_implementation/g1/sparsePRT.hpp
index 86d5db162..5cc884621 100644
--- a/src/share/vm/gc_implementation/g1/sparsePRT.hpp
+++ b/src/share/vm/gc_implementation/g1/sparsePRT.hpp
@@ -25,7 +25,7 @@
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_SPARSEPRT_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_SPARSEPRT_HPP
-#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
+#include "gc_implementation/g1/g1CollectedHeap.hpp"
#include "gc_implementation/g1/heapRegion.hpp"
#include "memory/allocation.hpp"
#include "memory/cardTableModRefBS.hpp"
diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
index 6ee151006..eb7de64f4 100644
--- a/src/share/vm/prims/jni.cpp
+++ b/src/share/vm/prims/jni.cpp
@@ -5208,7 +5208,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, v
}
#ifndef PRODUCT
- #ifndef TARGET_OS_FAMILY_windows
+ #ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED
#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f()
#endif
diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp
index 9f28fc2f1..7441f2610 100644
--- a/src/share/vm/runtime/arguments.cpp
+++ b/src/share/vm/runtime/arguments.cpp
@@ -1880,24 +1880,22 @@ static bool verify_serial_gc_flags() {
// check if do gclog rotation
// +UseGCLogFileRotation is a must,
// no gc log rotation when log file not supplied or
-// NumberOfGCLogFiles is 0, or GCLogFileSize is 0
+// NumberOfGCLogFiles is 0
void check_gclog_consistency() {
if (UseGCLogFileRotation) {
- if ((Arguments::gc_log_filename() == NULL) ||
- (NumberOfGCLogFiles == 0) ||
- (GCLogFileSize == 0)) {
+ if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) {
jio_fprintf(defaultStream::output_stream(),
- "To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files> -XX:GCLogFileSize=<num_of_size>[k|K|m|M|g|G]\n"
- "where num_of_file > 0 and num_of_size > 0\n"
+ "To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files>\n"
+ "where num_of_file > 0\n"
"GC log rotation is turned off\n");
UseGCLogFileRotation = false;
}
}
- if (UseGCLogFileRotation && GCLogFileSize < 8*K) {
- FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K);
- jio_fprintf(defaultStream::output_stream(),
- "GCLogFileSize changed to minimum 8K\n");
+ if (UseGCLogFileRotation && (GCLogFileSize != 0) && (GCLogFileSize < 8*K)) {
+ FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K);
+ jio_fprintf(defaultStream::output_stream(),
+ "GCLogFileSize changed to minimum 8K\n");
}
}
diff --git a/src/share/vm/runtime/globals.cpp b/src/share/vm/runtime/globals.cpp
index 74f7acdba..801f7b89a 100644
--- a/src/share/vm/runtime/globals.cpp
+++ b/src/share/vm/runtime/globals.cpp
@@ -325,7 +325,7 @@ void Flag::print_on(outputStream* st, bool withComments) {
else st->print("%-16s", "");
}
- st->print("%-20");
+ st->print("%-20s", " ");
print_kind(st);
if (withComments) {
diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
index ff05111e9..9927eb79f 100644
--- a/src/share/vm/runtime/globals.hpp
+++ b/src/share/vm/runtime/globals.hpp
@@ -2422,9 +2422,9 @@ class CommandLineFlags {
"Number of gclog files in rotation " \
"(default: 0, no rotation)") \
\
- product(uintx, GCLogFileSize, 0, \
- "GC log file size (default: 0 bytes, no rotation). " \
- "It requires UseGCLogFileRotation") \
+ product(uintx, GCLogFileSize, 8*K, \
+ "GC log file size, requires UseGCLogFileRotation. " \
+ "Set to 0 to only trigger rotation via jcmd") \
\
/* JVMTI heap profiling */ \
\
diff --git a/src/share/vm/runtime/safepoint.cpp b/src/share/vm/runtime/safepoint.cpp
index 48e523f5a..cac23e97e 100644
--- a/src/share/vm/runtime/safepoint.cpp
+++ b/src/share/vm/runtime/safepoint.cpp
@@ -535,7 +535,7 @@ void SafepointSynchronize::do_cleanup_tasks() {
// rotate log files?
if (UseGCLogFileRotation) {
- gclog_or_tty->rotate_log();
+ gclog_or_tty->rotate_log(false);
}
if (MemTracker::is_on()) {
diff --git a/src/share/vm/runtime/vm_operations.hpp b/src/share/vm/runtime/vm_operations.hpp
index ca616a52c..0cb3a18f9 100644
--- a/src/share/vm/runtime/vm_operations.hpp
+++ b/src/share/vm/runtime/vm_operations.hpp
@@ -94,6 +94,7 @@
template(JFRCheckpoint) \
template(Exit) \
template(LinuxDllLoad) \
+ template(RotateGCLog) \
class VM_Operation: public CHeapObj<mtInternal> {
public:
@@ -397,4 +398,15 @@ class VM_Exit: public VM_Operation {
void doit();
};
+
+class VM_RotateGCLog: public VM_Operation {
+ private:
+ outputStream* _out;
+
+ public:
+ VM_RotateGCLog(outputStream* st) : _out(st) {}
+ VMOp_Type type() const { return VMOp_RotateGCLog; }
+ void doit() { gclog_or_tty->rotate_log(true, _out); }
+};
+
#endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP
diff --git a/src/share/vm/services/diagnosticCommand.cpp b/src/share/vm/services/diagnosticCommand.cpp
index 71b552801..1245b5aaf 100644
--- a/src/share/vm/services/diagnosticCommand.cpp
+++ b/src/share/vm/services/diagnosticCommand.cpp
@@ -53,6 +53,7 @@ void DCmdRegistrant::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
#endif // INCLUDE_SERVICES
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
+ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
// Enhanced JMX Agent Support
// These commands won't be exported via the DiagnosticCommandMBean until an
@@ -650,3 +651,11 @@ void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) {
JavaCalls::call_static(&result, ik, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK);
}
+void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
+ if (UseGCLogFileRotation) {
+ VM_RotateGCLog rotateop(output());
+ VMThread::execute(&rotateop);
+ } else {
+ output()->print_cr("Target VM does not support GC log file rotation.");
+ }
+}
diff --git a/src/share/vm/services/diagnosticCommand.hpp b/src/share/vm/services/diagnosticCommand.hpp
index 5485b119d..2ce410998 100644
--- a/src/share/vm/services/diagnosticCommand.hpp
+++ b/src/share/vm/services/diagnosticCommand.hpp
@@ -360,4 +360,21 @@ public:
virtual void execute(DCmdSource source, TRAPS);
};
+class RotateGCLogDCmd : public DCmd {
+public:
+ RotateGCLogDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
+ static const char* name() { return "GC.rotate_log"; }
+ static const char* description() {
+ return "Force the GC log file to be rotated.";
+ }
+ static const char* impact() { return "Low"; }
+ virtual void execute(DCmdSource source, TRAPS);
+ static int num_arguments() { return 0; }
+ static const JavaPermission permission() {
+ JavaPermission p = {"java.lang.management.ManagementPermission",
+ "control", NULL};
+ return p;
+ }
+};
+
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
diff --git a/src/share/vm/utilities/ostream.cpp b/src/share/vm/utilities/ostream.cpp
index 90b3559e4..e09dfccf1 100644
--- a/src/share/vm/utilities/ostream.cpp
+++ b/src/share/vm/utilities/ostream.cpp
@@ -662,13 +662,13 @@ void gcLogFileStream::write(const char* s, size_t len) {
// write to gc log file at safepoint. If in future, changes made for mutator threads or
// concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
// must be synchronized.
-void gcLogFileStream::rotate_log() {
+void gcLogFileStream::rotate_log(bool force, outputStream* out) {
char time_msg[FILENAMEBUFLEN];
char time_str[EXTRACHARLEN];
char current_file_name[FILENAMEBUFLEN];
char renamed_file_name[FILENAMEBUFLEN];
- if (_bytes_written < (jlong)GCLogFileSize) {
+ if (!should_rotate(force)) {
return;
}
@@ -685,6 +685,11 @@ void gcLogFileStream::rotate_log() {
jio_snprintf(time_msg, sizeof(time_msg), "File %s rotated at %s\n",
_file_name, os::local_time_string((char *)time_str, sizeof(time_str)));
write(time_msg, strlen(time_msg));
+
+ if (out != NULL) {
+ out->print(time_msg);
+ }
+
dump_loggc_header();
return;
}
@@ -706,12 +711,18 @@ void gcLogFileStream::rotate_log() {
_file_name, _cur_file_num);
jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
_file_name, _cur_file_num);
- jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the"
- " maximum size. Saved as %s\n",
- os::local_time_string((char *)time_str, sizeof(time_str)),
- renamed_file_name);
+
+ const char* msg = force ? "GC log rotation request has been received."
+ : "GC log file has reached the maximum size.";
+ jio_snprintf(time_msg, sizeof(time_msg), "%s %s Saved as %s\n",
+ os::local_time_string((char *)time_str, sizeof(time_str)),
+ msg, renamed_file_name);
write(time_msg, strlen(time_msg));
+ if (out != NULL) {
+ out->print(time_msg);
+ }
+
fclose(_file);
_file = NULL;
@@ -752,6 +763,11 @@ void gcLogFileStream::rotate_log() {
os::local_time_string((char *)time_str, sizeof(time_str)),
current_file_name);
write(time_msg, strlen(time_msg));
+
+ if (out != NULL) {
+ out->print(time_msg);
+ }
+
dump_loggc_header();
// remove the existing file
if (access(current_file_name, F_OK) == 0) {
diff --git a/src/share/vm/utilities/ostream.hpp b/src/share/vm/utilities/ostream.hpp
index 20e6f30bf..b783787e0 100644
--- a/src/share/vm/utilities/ostream.hpp
+++ b/src/share/vm/utilities/ostream.hpp
@@ -115,7 +115,7 @@ class outputStream : public ResourceObj {
// flushing
virtual void flush() {}
virtual void write(const char* str, size_t len) = 0;
- virtual void rotate_log() {} // GC log rotation
+ virtual void rotate_log(bool force, outputStream* out = NULL) {} // GC log rotation
virtual ~outputStream() {} // close properly on deletion
void dec_cr() { dec(); cr(); }
@@ -240,8 +240,15 @@ class gcLogFileStream : public fileStream {
gcLogFileStream(const char* file_name);
~gcLogFileStream();
virtual void write(const char* c, size_t len);
- virtual void rotate_log();
+ virtual void rotate_log(bool force, outputStream* out = NULL);
void dump_loggc_header();
+
+ /* If "force" sets true, force log file rotation from outside JVM */
+ bool should_rotate(bool force) {
+ return force ||
+ ((GCLogFileSize != 0) && ((uintx)_bytes_written >= GCLogFileSize));
+ }
+
};
#ifndef PRODUCT