--- old/src/share/vm/gc_implementation/shared/gcTrace.cpp 2013-05-07 14:49:31.624167960 +0200 +++ new/src/share/vm/gc_implementation/shared/gcTrace.cpp 2013-05-07 14:49:31.556167962 +0200 @@ -91,16 +91,32 @@ send_reference_stats_event(REF_PHANTOM, rps.phantom_count()); } -class ObjectCountEventSenderClosure : public KlassInfoClosure { - GCTracer* _gc_tracer; - public: - ObjectCountEventSenderClosure(GCTracer* gc_tracer) : _gc_tracer(gc_tracer) {} - private: - void do_cinfo(KlassInfoEntry* entry) { - _gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(), - entry->words() * BytesPerWord); +void ObjectCountEventSenderClosure::do_cinfo(KlassInfoEntry* entry) { + if (should_send_event(entry)) { + send_event(entry); } -}; +} + +void ObjectCountEventSenderClosure::send_event(KlassInfoEntry* entry) { + _gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(), + entry->words() * BytesPerWord); +} + +bool ObjectCountEventSenderClosure::should_send_event(KlassInfoEntry* entry) const { + double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; + return percentage_of_heap > _size_threshold_percentage; +} + +bool ObjectCountFilter::do_object_b(oop obj) { + bool is_alive = _is_alive == NULL? true : _is_alive->do_object_b(obj); + return is_alive && is_externally_visible_klass(obj->klass()); +} + +bool ObjectCountFilter::is_externally_visible_klass(klassOop k) const { + // Do not expose internal implementation specific classes + return (k->klass_part()->oop_is_instance() || k->klass_part()->oop_is_array()) && + k != Universe::systemObjArrayKlassObj(); +} void GCTracer::report_object_count_after_gc(BoolObjectClosure *is_alive_cl) { if (should_send_object_count_after_gc_event()) { @@ -108,8 +124,11 @@ KlassInfoTable cit(HeapInspection::start_of_perm_gen()); if (!cit.allocation_failed()) { - ObjectCountEventSenderClosure event_sender(this); - HeapInspection::instance_inspection(&cit, &event_sender, false, is_alive_cl); + ObjectCountFilter object_filter(is_alive_cl); + HeapInspection::populate_table(&cit, false, &object_filter); + + ObjectCountEventSenderClosure event_sender(this, cit.size_of_instances_in_words()); + cit.iterate(&event_sender); } } } --- old/src/share/vm/gc_implementation/shared/gcTrace.hpp 2013-05-07 14:49:31.980167946 +0200 +++ new/src/share/vm/gc_implementation/shared/gcTrace.hpp 2013-05-07 14:49:31.908167949 +0200 @@ -30,6 +30,7 @@ #include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/copyFailedInfo.hpp" #include "memory/allocation.hpp" +#include "memory/klassInfoClosure.hpp" #include "memory/referenceType.hpp" #ifndef SERIALGC #include "gc_implementation/g1/g1YCTypes.hpp" @@ -110,6 +111,33 @@ #endif // SERIALGC +class ObjectCountEventSenderClosure : public KlassInfoClosure { + GCTracer* _gc_tracer; + const double _size_threshold_percentage; + const size_t _total_size_in_words; + public: + ObjectCountEventSenderClosure(GCTracer* gc_tracer, size_t total_size_in_words) : + _gc_tracer(gc_tracer), + _size_threshold_percentage(ObjectCountCutOffPercent / 100), + _total_size_in_words(total_size_in_words) + {} + virtual void do_cinfo(KlassInfoEntry* entry); + protected: + virtual void send_event(KlassInfoEntry* entry); + private: + bool should_send_event(KlassInfoEntry* entry) const; +}; + +class ObjectCountFilter : public BoolObjectClosure { + BoolObjectClosure* _is_alive; + public: + ObjectCountFilter(BoolObjectClosure* is_alive = NULL) : _is_alive(is_alive) {} + bool do_object_b(oop obj); + void do_object(oop obj) { ShouldNotReachHere(); } + private: + bool is_externally_visible_klass(klassOop k) const; +}; + class GCTracer : public ResourceObj { friend class ObjectCountEventSenderClosure; protected: --- old/src/share/vm/memory/heapInspection.cpp 2013-05-07 14:49:32.352167931 +0200 +++ new/src/share/vm/memory/heapInspection.cpp 2013-05-07 14:49:32.284167935 +0200 @@ -113,9 +113,8 @@ } } -KlassInfoTable::KlassInfoTable(HeapWord* ref) { - _size = 0; - _ref = ref; +KlassInfoTable::KlassInfoTable(HeapWord* ref) : + _size(0), _ref(ref), _size_of_instances_in_words(0) { _buckets = (KlassInfoBucket *) os::malloc(sizeof(KlassInfoBucket) * _num_buckets, mtInternal); if (_buckets != NULL) { _size = _num_buckets; @@ -160,6 +159,7 @@ if (elt != NULL) { elt->set_count(elt->count() + 1); elt->set_words(elt->words() + obj->size()); + _size_of_instances_in_words += obj->size(); return true; } else { return false; @@ -173,6 +173,10 @@ } } +size_t KlassInfoTable::size_of_instances_in_words() const { + return _size_of_instances_in_words; +} + int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { return (*e1)->compare(*e1,*e2); } @@ -282,10 +286,9 @@ } } -size_t HeapInspection::instance_inspection(KlassInfoTable* cit, - KlassInfoClosure* cl, - bool need_prologue, - BoolObjectClosure* filter) { +size_t HeapInspection::populate_table(KlassInfoTable* cit, + bool need_prologue, + BoolObjectClosure *filter) { ResourceMark rm; if (need_prologue) { @@ -294,7 +297,6 @@ RecordInstanceClosure ric(cit, filter); Universe::heap()->object_iterate(&ric); - cit->iterate(cl); // need to run epilogue if we run prologue if (need_prologue) { @@ -309,17 +311,20 @@ KlassInfoTable cit(start_of_perm_gen()); if (!cit.allocation_failed()) { - KlassInfoHisto histo("\n" - " num #instances #bytes class name\n" - "----------------------------------------------"); - HistoClosure hc(&histo); - - size_t missed_count = instance_inspection(&cit, &hc, need_prologue); + size_t missed_count = populate_table(&cit, need_prologue); if (missed_count != 0) { st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT " total instances in data below", missed_count); } + + KlassInfoHisto histo("\n" + " num #instances #bytes class name\n" + "----------------------------------------------"); + HistoClosure hc(&histo); + + cit.iterate(&hc); + histo.sort(); histo.print_on(st); } else { --- old/src/share/vm/memory/heapInspection.hpp 2013-05-07 14:49:32.732167917 +0200 +++ new/src/share/vm/memory/heapInspection.hpp 2013-05-07 14:49:32.660167921 +0200 @@ -26,6 +26,7 @@ #define SHARE_VM_MEMORY_HEAPINSPECTION_HPP #include "memory/allocation.inline.hpp" +#include "memory/klassInfoClosure.hpp" #include "oops/oop.inline.hpp" @@ -64,12 +65,6 @@ void print_on(outputStream* st) const; }; -class KlassInfoClosure: public StackObj { - public: - // Called for each KlassInfoEntry. - virtual void do_cinfo(KlassInfoEntry* cie) = 0; -}; - class KlassInfoBucket: public CHeapObj { private: KlassInfoEntry* _list; @@ -86,6 +81,7 @@ private: int _size; static const int _num_buckets = 20011; + size_t _size_of_instances_in_words; // An aligned reference address (typically the least // address in the perm gen) used for hashing klass @@ -102,6 +98,7 @@ bool record_instance(const oop obj); void iterate(KlassInfoClosure* cic); bool allocation_failed() { return _buckets == NULL; } + size_t size_of_instances_in_words() const; }; class KlassInfoHisto : public StackObj { @@ -125,10 +122,9 @@ class HeapInspection : public AllStatic { public: static void heap_inspection(outputStream* st, bool need_prologue); - static size_t instance_inspection(KlassInfoTable* cit, - KlassInfoClosure* cl, - bool need_prologue, - BoolObjectClosure* filter = NULL); + static size_t populate_table(KlassInfoTable* cit, + bool need_prologue, + BoolObjectClosure* filter = NULL); static HeapWord* start_of_perm_gen(); static void find_instances_at_safepoint(klassOop k, GrowableArray* result); private: --- old/src/share/vm/runtime/globals.hpp 2013-05-07 14:49:33.084167905 +0200 +++ new/src/share/vm/runtime/globals.hpp 2013-05-07 14:49:33.004167908 +0200 @@ -2302,6 +2302,10 @@ "Print diagnostic message when GC is stalled" \ "by JNI critical section") \ \ + product(double, ObjectCountCutOffPercent, 0.5, \ + "The percentage of the used heap that the instances of a class " \ + "must occupy for the class to generate an eventual trace event.") \ + \ /* GC log rotation setting */ \ \ product(bool, UseGCLogFileRotation, false, \ --- /dev/null 2013-05-07 08:22:24.945044734 +0200 +++ new/src/share/vm/memory/klassInfoClosure.hpp 2013-05-07 14:49:33.412167891 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP +#define SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP + +class KlassInfoEntry; + +class KlassInfoClosure : public StackObj { + public: + // Called for each KlassInfoEntry. + virtual void do_cinfo(KlassInfoEntry* cie) = 0; +}; + +#endif // SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP