src/share/vm/runtime/sweeper.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File
*** old/src/share/vm/runtime/sweeper.cpp	Wed May  7 00:02:28 2014
--- new/src/share/vm/runtime/sweeper.cpp	Wed May  7 00:02:27 2014

*** 567,578 **** --- 567,591 ---- nm->make_zombie(); _zombified_count++; SWEEP(nm); } } else { + possibly_flush(nm); + // Clean-up all inline caches that point to zombie/non-reentrant methods + MutexLocker cl(CompiledIC_lock); + nm->cleanup_inline_caches(); + SWEEP(nm); + } + return freed_memory; + } + + + void NMethodSweeper::possibly_flush(nmethod* nm) { if (UseCodeCacheFlushing) { if (!nm->is_locked_by_vm() && !nm->is_osr_method() && !nm->is_native_method()) { + bool make_not_entrant = false; + // Do not make native methods and OSR-methods not-entrant nm->dec_hotness_counter(); // Get the initial value of the hotness counter. This value depends on the // ReservedCodeCacheSize int reset_val = hotness_counter_reset_val();
*** 581,613 **** --- 594,663 ---- // The less free space in the code cache we have - the bigger reverse_free_ratio() is. // I.e., 'threshold' increases with lower available space in the code cache and a higher // NmethodSweepActivity. If the current hotness counter - which decreases from its initial // value until it is reset by stack walking - is smaller than the computed threshold, the // corresponding nmethod is considered for removal. ! if ((NmethodSweepActivity > 0) && (nm->hotness_counter() < threshold) && (time_since_reset > 10)) { ! if ((NmethodSweepActivity > 0) && (nm->hotness_counter() < threshold) && (time_since_reset > MinPassesBeforeFlush)) { // A method is marked as not-entrant if the method is // 1) 'old enough': nm->hotness_counter() < threshold ! // 2) The method was in_use for a minimum amount of time: (time_since_reset > 10) ! // 2) The method was in_use for a minimum amount of time: (time_since_reset > MinPassesBeforeFlush) // The second condition is necessary if we are dealing with very small code cache // sizes (e.g., <10m) and the code cache size is too small to hold all hot methods. // The second condition ensures that methods are not immediately made not-entrant // after compilation. + make_not_entrant = true; + } + + // The stack-scanning low-cost detection didn't see the method used (which can happen for + // flat profiles). Check the age counter for possible data. + if (UseCodeAging && make_not_entrant && (nm->is_compiled_by_c2() || nm->is_compiled_by_c1())) { + MethodCounters* mc = nm->method()->method_counters(); + if (mc != NULL) { + // Snapshot the value as it's changed concurrently + int age = mc->nmethod_age(); + if (MethodCounters::is_nmethod_hot(age)) { + // The method has gone through flushing, and it became relatively hot that it deopted + // before we could take a look at it. + if (time_since_reset > MinPassesBeforeFlush * 2) { + // It's been long enough, we still haven't seen it on stack. + // Try to flush it, but enable counters the next time. + mc->reset_nmethod_age(); + } else { + make_not_entrant = false; + } + } else if (MethodCounters::is_nmethod_warm(age)) { + // Method has counters enabled, and the method was used within + // previous 10 sweeps. Reset the counter. Stay in the existing + // compiled state. + mc->reset_nmethod_age(); + // delay the next check + nm->set_hotness_counter(NMethodSweeper::hotness_counter_reset_val()); + make_not_entrant = false; + } else if (MethodCounters::is_nmethod_age_unset(age)) { + // No counters were used before. Set the counters to the detection + // limit value. If the method is going to be used again it will be compiled + // with counters that we're going to use for analysis the the next time. + mc->reset_nmethod_age(); + } else { + // Method was totally idle for 10 sweeps + // The counter already has the initial value, flush it and may be recompile + // later with counters + } + } + } + + if (make_not_entrant) { nm->make_not_entrant(); + // Code cache state change is tracked in make_not_entrant() if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %d/" PTR_FORMAT "made not-entrant: hotness counter %d/%d threshold %f", nm->compile_id(), nm, nm->hotness_counter(), reset_val, threshold); } } } } // Clean-up all inline caches that point to zombie/non-reentrant methods MutexLocker cl(CompiledIC_lock); nm->cleanup_inline_caches(); SWEEP(nm); } return freed_memory; } // Print out some state information about the current sweep and the // state of the code cache if it's requested. void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) {

src/share/vm/runtime/sweeper.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File