Skip to content

Instantly share code, notes, and snippets.

@gvsmirnov
Created December 23, 2013 11:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gvsmirnov/8095512 to your computer and use it in GitHub Desktop.
Save gvsmirnov/8095512 to your computer and use it in GitHub Desktop.
GCCause::_last_ditch_collection and GCCause::_no_gc
$ grep -rn -C 4 GCCause::_no_gc hotspot/src
./share/vm/gc_implementation/shared/vmGCOperations.cpp-86-}
./share/vm/gc_implementation/shared/vmGCOperations.cpp-87-
./share/vm/gc_implementation/shared/vmGCOperations.cpp-88-bool VM_GC_Operation::doit_prologue() {
./share/vm/gc_implementation/shared/vmGCOperations.cpp-89-  assert(Thread::current()->is_Java_thread(), "just checking");
./share/vm/gc_implementation/shared/vmGCOperations.cpp:90:  assert(((_gc_cause != GCCause::_no_gc) &&
./share/vm/gc_implementation/shared/vmGCOperations.cpp-91-          (_gc_cause != GCCause::_no_cause_specified)), "Illegal GCCause");
./share/vm/gc_implementation/shared/vmGCOperations.cpp-92-
./share/vm/gc_implementation/shared/vmGCOperations.cpp-93-  acquire_pending_list_lock();
./share/vm/gc_implementation/shared/vmGCOperations.cpp-94-  // If the GC count has changed someone beat us to the collection
--
./share/vm/gc_interface/collectedHeap.cpp-60-
./share/vm/gc_interface/collectedHeap.cpp-61-  _barrier_set = NULL;
./share/vm/gc_interface/collectedHeap.cpp-62-  _is_gc_active = false;
./share/vm/gc_interface/collectedHeap.cpp-63-  _total_collections = _total_full_collections = 0;
./share/vm/gc_interface/collectedHeap.cpp:64:  _gc_cause = _gc_lastcause = GCCause::_no_gc;
./share/vm/gc_interface/collectedHeap.cpp-65-  NOT_PRODUCT(_promotion_failure_alot_count = 0;)
./share/vm/gc_interface/collectedHeap.cpp-66-  NOT_PRODUCT(_promotion_failure_alot_gc_number = 0;)
./share/vm/gc_interface/collectedHeap.cpp-67-
./share/vm/gc_interface/collectedHeap.cpp-68-  if (UsePerfData) {
--
./share/vm/memory/permGen.cpp-40-
./share/vm/memory/permGen.cpp-41-HeapWord* PermGen::request_expand_and_allocate(Generation* gen, size_t size,
./share/vm/memory/permGen.cpp-42-                                               GCCause::Cause prev_cause) {
./share/vm/memory/permGen.cpp-43-  if (gen->capacity() < _capacity_expansion_limit ||
./share/vm/memory/permGen.cpp:44:      prev_cause != GCCause::_no_gc || UseG1GC) {  // last disjunct is a temporary hack for G1
./share/vm/memory/permGen.cpp-45-    return gen->expand_and_allocate(size, false);
./share/vm/memory/permGen.cpp-46-  }
./share/vm/memory/permGen.cpp-47-  // We have reached the limit of capacity expansion where
./share/vm/memory/permGen.cpp-48-  // we will not expand further until a GC is done; request denied.
--
./share/vm/memory/permGen.cpp-50-}
./share/vm/memory/permGen.cpp-51-
./share/vm/memory/permGen.cpp-52-HeapWord* PermGen::mem_allocate_in_gen(size_t size, Generation* gen) {
./share/vm/memory/permGen.cpp-53-  GCCause::Cause next_cause = GCCause::_permanent_generation_full;
./share/vm/memory/permGen.cpp:54:  GCCause::Cause prev_cause = GCCause::_no_gc;
./share/vm/memory/permGen.cpp-55-  unsigned int gc_count_before, full_gc_count_before;
./share/vm/memory/permGen.cpp-56-  HeapWord* obj;
./share/vm/memory/permGen.cpp-57-
./share/vm/memory/permGen.cpp-58-  for (;;) {

So, we have two reads and two writes. The one in collectedHeap.cpp is initialization in constructor. The other one is when we are trying to allocate more memory for permgen, apparently:

HeapWord* mem_allocate_in_gen(size_t size, Generation* gen);
// Along with mem_allocate_in_gen() above, implements policy for
// "scheduling" allocation/expansion/collection of the perm gen.
// The virtual method request_...() below can be overridden by
// subtypes that want to implement a different expansion/collection
// policy from the default provided.

Is only invoked once:

HeapWord* CompactingPermGen::mem_allocate(size_t size) {
  return mem_allocate_in_gen(size, _gen);
}

As for GCCause::_last_ditch_collection, it is only set once in the end of PermGen::mem_allocate_in_gen:

./share/vm/memory/permGen.cpp-115-    prev_cause = next_cause;
./share/vm/memory/permGen.cpp:116:    next_cause = GCCause::_last_ditch_collection;
./share/vm/memory/permGen.cpp-117-  }
@gvsmirnov
Copy link
Author

See also:

./share/vm/memory/genCollectedHeap.cpp-445-bool GenCollectedHeap::must_clear_all_soft_refs() {
./share/vm/memory/genCollectedHeap.cpp:446:  return _gc_cause == GCCause::_last_ditch_collection;
./share/vm/memory/genCollectedHeap.cpp-447-}
./share/vm/memory/permGen.cpp-68-      // Concurrent collectors may decide to kick off a concurrent
./share/vm/memory/permGen.cpp-69-      // collection under appropriate conditions.
./share/vm/memory/permGen.cpp-70-      obj = request_expand_and_allocate(gen, size, prev_cause);
./share/vm/memory/permGen.cpp-71-
./share/vm/memory/permGen.cpp:72:      if (obj != NULL || prev_cause == GCCause::_last_ditch_collection) {
./share/vm/memory/permGen.cpp-73-        return obj;
./share/vm/memory/permGen.cpp-74-      }

@iNikem
Copy link

iNikem commented Dec 23, 2013

I am still no smarter :) If I see in my logs, that the cause for GC is "No GC", what does it mean? Why this GC was triggered?

@gvsmirnov
Copy link
Author

@iNikem seems pretty straightforward to me. That's likely to only happen when the VM is allocating/expanding the perm gen. I haven't looked further yet, but given the above, it's the obvious conclusion. Can't investigate at the moment. Besides, don't want to steal all the fun from you :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment