Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/hotspot/share/gc/g1/g1CollectedHeap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,9 @@ class G1CollectedHeap : public CollectedHeap {
// requires.
static size_t humongous_obj_size_in_regions(size_t word_size);

// Returns whether the given array has oops or not in its body.
inline static bool array_has_oops(oop obj);

// Returns how much space in bytes an allocation of word_size will use up in the
// heap.
static size_t allocation_used_bytes(size_t word_size);
Expand Down
8 changes: 8 additions & 0 deletions src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "gc/shared/collectedHeap.inline.hpp"
#include "gc/shared/markBitMap.inline.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/stackChunkOop.hpp"
#include "runtime/threadSMR.inline.hpp"
#include "utilities/bitMap.inline.hpp"
Expand Down Expand Up @@ -109,6 +110,13 @@ inline G1HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.
// Return the region with the given index, or null if unmapped. It assumes the index is valid.
inline G1HeapRegion* G1CollectedHeap::region_at_or_null(uint index) const { return _hrm.at_or_null(index); }

inline bool G1CollectedHeap::array_has_oops(oop obj) {
assert(obj->is_array(), "must be");
// Just assume that any instanceOops always have references, i.e. they return "false" although
// they may or may not have references.
return obj->is_array_with_oops();
}

template <typename Func>
inline void G1CollectedHeap::humongous_obj_regions_iterate(G1HeapRegion* start, const Func& f) {
assert(start->is_starts_humongous(), "must be");
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,10 @@ class G1CMTask : public TerminatorTerminator {
// mark bitmap scan, and so needs to be pushed onto the mark stack.
bool is_below_finger(oop obj, HeapWord* global_finger) const;

// Returns whether the given oop can be processed immediately, i.e. does not need
// to be pushed into the mark stack.
// Note that even with a true result, the klass may need to be inspected.
static bool can_be_processed_immediately(oop obj);
template<bool scan> void process_grey_task_entry(G1TaskQueueEntry task_entry, bool stolen);

static bool should_be_sliced(oop obj);
Expand Down
18 changes: 13 additions & 5 deletions src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ inline bool G1CMTask::is_below_finger(oop obj, HeapWord* global_finger) const {

template<bool scan>
inline void G1CMTask::process_grey_task_entry(G1TaskQueueEntry task_entry, bool stolen) {
assert(scan || (!task_entry.is_partial_array_state() && task_entry.to_oop()->is_typeArray()), "Skipping scan of grey non-typeArray");
assert(scan || (!task_entry.is_partial_array_state() && !G1CollectedHeap::array_has_oops(task_entry.to_oop())),
"Skipping scan of grey object that needs scanning");
assert(task_entry.is_partial_array_state() || _mark_bitmap->is_marked(cast_from_oop<HeapWord*>(task_entry.to_oop())),
"Any stolen object should be a slice or marked");

Expand All @@ -177,10 +178,17 @@ inline void G1CMTask::process_grey_task_entry(G1TaskQueueEntry task_entry, bool
_words_scanned += obj->oop_iterate_size(_cm_oop_closure);
}
}
} else if (!task_entry.to_oop()->is_typeArray()) {
// Need to process the klass except for the built-in type array.
_cm_oop_closure->do_klass(task_entry.to_oop()->klass());
}
check_limits();
}

inline bool G1CMTask::can_be_processed_immediately(oop obj) {
return obj->is_array() && !G1CollectedHeap::array_has_oops(obj);
}

inline bool G1CMTask::should_be_sliced(oop obj) {
return obj->is_array_with_oops() && ((objArrayOop)obj)->length() >= (int)ObjArrayMarkingStride;
}
Expand Down Expand Up @@ -274,17 +282,17 @@ inline bool G1CMTask::make_reference_grey(oop obj) {
// correctness problems.
if (is_below_finger(obj, global_finger)) {
G1TaskQueueEntry entry(obj);
if (obj->is_typeArray()) {
// Immediately process arrays of primitive types, rather
if (can_be_processed_immediately(obj)) {
// Immediately process arrays of types without oops, rather
// than pushing on the mark stack. This keeps us from
// adding humongous objects to the mark stack that might
// be reclaimed before the entry is processed - see
// selection of candidates for eager reclaim of humongous
// objects. The cost of the additional type test is
// mitigated by avoiding a trip through the mark stack,
// by only doing a bookkeeping update and avoiding the
// actual scan of the object - a typeArray contains no
// references, and the metadata is built-in.
// actual scan of the object - the object contains no
// references (but the metadata must be processed).
process_grey_task_entry<false>(entry, false /* stolen */);
} else {
push(entry);
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/gc/g1/g1FullCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

#include "classfile/classLoaderDataGraph.hpp"
#include "cppstdlib/new.hpp"
#include "gc/g1/g1CollectedHeap.hpp"
//#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1FullCollector.inline.hpp"
#include "gc/g1/g1FullGCAdjustTask.hpp"
#include "gc/g1/g1FullGCCompactTask.hpp"
Expand Down
33 changes: 18 additions & 15 deletions src/hotspot/share/gc/g1/g1YoungCollector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,13 +341,14 @@ class G1PrepareEvacuationTask : public WorkerTask {
// It also helps with G1 allocating humongous objects as old generation
// objects although they might also die quite quickly.
//
// TypeArray objects are allowed to be reclaimed even if allocated before
// Humongous objects without oops (typeArrays, flatArrays without oops in
// its elements) are allowed to be reclaimed even if allocated before
// the start of concurrent mark. For this we rely on mark stack insertion
// to exclude is_typeArray() objects, preventing reclaiming an object
// that is in the mark stack. We also rely on the metadata for
// such objects to be built-in and so ensured to be kept live.
// to exclude them, preventing reclaiming an object
// that is in the mark stack. That code also ensures that metadata (klass)
// is kept live.
//
// Non-typeArrays that were allocated before marking are excluded from
// Other humongous objects that were allocated before marking are excluded from
// eager reclaim during marking. One issue is the problem described
// above with scrubbing the mark stack, but there is also a problem
// causing these humongous objects being collected incorrectly:
Expand All @@ -362,16 +363,17 @@ class G1PrepareEvacuationTask : public WorkerTask {
// garbage collection. o1 still has the reference to o2, but since o1 had
// already been scanned we do not detect o2 to be still live and reclaim it.
//
// There is another minor problem with non-typeArray regions being the source
// of remembered set entries in other region's remembered sets. There are
// two cases: first, the remembered set entry is in a Free region after reclaim.
// We handle this case by ignoring these cards during merging the remembered
// sets.
// There is another minor problem with these humongous objects with oops being
// the source of remembered set entries in other region's remembered sets.
// There are two cases: first, the remembered set entry is in a Free region
// after reclaim. We handle this case by ignoring these cards during merging
// the remembered sets.
//
// Second, there may be cases where eagerly reclaimed regions were already
// reallocated. This may cause scanning of these outdated remembered set
// entries, containing some objects. But apart from extra work this does
// not cause correctness issues.
// Second, there may be cases where regions previously containing eagerly
// reclaimed objects were already allocated into again.
// This may cause scanning of these outdated remembered set entries,
// containing some objects. But apart from extra work this does not cause
// correctness issues.
// There is no difference between scanning cards covering an effectively
// dead humongous object vs. some other objects in reallocated regions.
//
Expand All @@ -388,7 +390,8 @@ class G1PrepareEvacuationTask : public WorkerTask {
//
// After the pause, having reclaimed h, obviously the mutator can't fetch
// the reference from h any more.
if (!obj->is_typeArray()) {
bool potentially_has_oops = !obj->is_array() || _g1h->array_has_oops(obj);
if (potentially_has_oops) {
// All regions that were allocated before marking have a TAMS != bottom.
bool allocated_before_mark_start = region->bottom() != _g1h->concurrent_mark()->top_at_mark_start(region);
bool mark_in_progress = _g1h->collector_state()->mark_in_progress();
Expand Down
9 changes: 5 additions & 4 deletions src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,10 +396,11 @@ class G1FreeHumongousRegionClosure : public G1HeapRegionIndexClosure {
ResourceMark rm;
bool allocated_after_mark_start = r->bottom() == _g1h->concurrent_mark()->top_at_mark_start(r);
bool mark_in_progress = _g1h->collector_state()->mark_in_progress();
guarantee(obj->is_typeArray() || (allocated_after_mark_start || !mark_in_progress),
"Only eagerly reclaiming primitive arrays is supported, other humongous objects only if allocated after mark start, but the object "
PTR_FORMAT " (%s) is not (mark %d allocated after mark: %d).",
p2i(r->bottom()), obj->klass()->name()->as_C_string(), mark_in_progress, allocated_after_mark_start);
bool potentially_has_oops = !obj->is_array() || G1CollectedHeap::array_has_oops(obj);
guarantee(!potentially_has_oops || (allocated_after_mark_start || !mark_in_progress),
"Only eagerly reclaiming arrays without oops is always supported, other humongous objects only if allocated after mark start, but the object "
PTR_FORMAT " (%s) is not (allocated after mark: %d mark in progress %d).",
p2i(r->bottom()), obj->klass()->name()->as_C_string(), allocated_after_mark_start, mark_in_progress);
}
log_debug(gc, humongous)("Reclaimed humongous region %u (object size %zu @ " PTR_FORMAT ")",
region_index,
Expand Down
Loading