Mercurial > hg > release > heapstats-1.1
changeset 66:bbf1ae6d2a2e
Bug 3331: Refactoring for memory management in HeapStats Agent
Reviewed-by: ykubota
https://github.com/HeapStats/heapstats/pull/86
author | Yasumasa Suenaga <yasuenag@gmail.com> |
---|---|
date | Mon, 27 Feb 2017 19:25:26 +0900 |
parents | ef928edf1d20 |
children | 2518d4eee904 |
files | agent/src/classContainer.cpp agent/src/classContainer.hpp agent/src/snapShotContainer.cpp agent/src/snapShotContainer.hpp agent/src/snapShotMain.cpp agent/src/snapShotMain.hpp agent/src/snapShotProcessor.cpp agent/src/util.hpp |
diffstat | 8 files changed, 263 insertions(+), 379 deletions(-) [+] |
line wrap: on
line diff
--- a/agent/src/classContainer.cpp Thu Feb 09 12:31:27 2017 +0900 +++ b/agent/src/classContainer.cpp Mon Feb 27 19:25:26 2017 +0900 @@ -94,6 +94,11 @@ */ static char ORDER_DELTA[6] = "DELTA"; +static TClassInfoSet unloadedList; +volatile int unloadedList_lock = 0; + +extern TClassContainer *clsContainer; + /*! * \brief TClassContainer constructor. * \param base [in] Parent class container instance. @@ -108,7 +113,6 @@ needToClear = needToClr; classMap = NULL; pSender = NULL; - unloadedList = NULL; if (likely(base != NULL)) { @@ -144,9 +148,6 @@ pSender = new TTrapSender(SNMP_VERSION_2c, arg.snmpTarget, arg.snmpComName, 162); - /* Create unloaded class information queue. */ - unloadedList = new TClassInfoQueue(); - /* Create thread storage key. */ if (unlikely(pthread_key_create(&clsContainerKey, NULL) != 0)) { throw 1; @@ -154,7 +155,6 @@ } catch(...) { delete classMap; delete pSender; - delete unloadedList; throw "TClassContainer initialize failed!"; } } @@ -179,7 +179,6 @@ /* Cleanup instances. */ delete classMap; delete pSender; - delete unloadedList; /* Cleanup thread storage key. */ pthread_key_delete(clsContainerKey); @@ -243,7 +242,6 @@ free(cur); } - atomic_inc(&result->numRefs, 1); return result; } @@ -281,23 +279,14 @@ && objData->clsLoaderId == expectData->clsLoaderId)) { /* Return existing data on map. */ - /* - * We should not increment reference counter because - * we do not add reference. - */ existData = expectData; } else { - /* klass oop is doubling for another class. */ - removeClass(expectData); - try { - unloadedList->push(expectData); - } catch(...) { - /* - * We try to continue running without crash - * even if failed to allocate memory. - */ + spinLockWait(&unloadedList_lock); + { + unloadedList.insert(expectData); } + spinLockRelease(&unloadedList_lock); } } } @@ -327,10 +316,7 @@ /* Broadcast to each local container. */ for (TLocalClassContainer::iterator it = localContainers.begin(); it != localContainers.end(); it++) { - // We should skip myself if "this" ptr is in local container. - if (*it != this) { - (*it)->pushNewClass(klassOop, objData); - } + (*it)->pushNewClass(klassOop, objData); } } /* Release spin lock of containers queue. */ @@ -339,19 +325,6 @@ } /*! - * \brief Mark class in container to remove class. - * \param target [in] Remove class data. - */ -void TClassContainer::popClass(TObjectData *target) { - - /* - * This function isn't remove item from map. - * Remove item and deallocate memory at "commitClassChange". - */ - target->isRemoved = true; -} - -/*! * \brief Remove class from container. * \param target [in] Remove class data. */ @@ -359,7 +332,6 @@ /* Remove item from map. Please callee has container's lock. */ classMap->erase(target->klassOop); - atomic_inc(&target->numRefs, -1); /* Get spin lock of containers queue. */ spinLockWait(&queueLock); @@ -367,17 +339,11 @@ /* Broadcast to each local container. */ for (TLocalClassContainer::iterator it = localContainers.begin(); it != localContainers.end(); it++) { - // We should skip myself if "this" ptr is in local container. - if (*it != this) { - /* Get local container's spin lock. */ - spinLockWait(&(*it)->lockval); - { - (*it)->classMap->erase(target->klassOop); - atomic_inc(&target->numRefs, -1); - } - /* Release local container's spin lock. */ - spinLockRelease(&(*it)->lockval); - } + /* Get local container's spin lock. */ + spinLockWait(&(*it)->lockval); + { (*it)->classMap->erase(target->klassOop); } + /* Release local container's spin lock. */ + spinLockRelease(&(*it)->lockval); } } /* Release spin lock of containers queue. */ @@ -386,61 +352,22 @@ /*! * \brief Remove all-class from container. + * This function will be called from d'tor of TClassContainer. + * So we do not get any lock because d'tor calls at Agent_OnUnload. */ void TClassContainer::allClear(void) { - - /* Get spin lock of containers queue. */ - spinLockWait(&queueLock); - { - /* Broadcast to each local container. */ - for (TLocalClassContainer::iterator it = localContainers.begin(); - it != localContainers.end(); it++) { - - /* Get local container's spin lock. */ - spinLockWait(&(*it)->lockval); - { - (*it)->classMap->clear(); - } - /* Release local container's spin lock. */ - spinLockRelease(&(*it)->lockval); - } - } - /* Release spin lock of containers queue. */ - spinLockRelease(&queueLock); - - /* Get class container's spin lock. */ - spinLockWait(&lockval); - { - /* Free allocated memory at class map. */ - for (TClassMap::iterator cur = classMap->begin(); - cur != classMap->end(); ++cur) { - TObjectData *pos = (*cur).second; - - if (likely(pos != NULL)) { - /* Decrement reference from this class map. */ - atomic_inc(&pos->numRefs, -1); + /* Add all TObjectData pointers in parent container map to unloadedList */ + for (TClassMap::iterator cur = classMap->begin(); cur != classMap->end(); + ++cur) { + unloadedList.insert(cur->second); + } - if (atomic_get(&pos->numRefs) == 0) { - free(pos->className); - free(pos); - } - } - } - - /* Free allocated memory at unloaded list. */ - while (!unloadedList->empty()) { - TObjectData *pos = unloadedList->front(); - unloadedList->pop(); - - free(pos->className); - free(pos); - } - - /* Clear all class. */ - classMap->clear(); - } - /* Release class container's spin lock. */ - spinLockRelease(&lockval); + /* Release all memory for TObjectData. */ + for (TClassInfoSet::iterator itr = unloadedList.begin(); + itr != unloadedList.end(); itr++) { + free((*itr)->className); + free(*itr); + } } /*! @@ -1021,77 +948,57 @@ } /*! - * \brief Commit class information changing in class container.<br> - * This function is for avoiding trouble with class map.<br> - * At "afterTakeSnapShot", map is copied as shadow copy.<br> - * So crash JVM, - * if we remove item and output map at the same times. + * \brief Class unload event. Unloaded class will be added to unloaded list. + * \param jvmti [in] JVMTI environment object. + * \param env [in] JNI environment object. + * \param thread [in] Java thread object. + * \param klass [in] Unload class object. + * \sa from: hotspot/src/share/vm/prims/jvmti.xml */ -void TClassContainer::commitClassChange(void) { - TClassInfoQueue *list = NULL; - - /* Get class container's spin lock. */ - spinLockWait(&lockval); - { - /* Remove unloaded class which detected at "pushNewClass". */ - while (!unloadedList->empty()) { - TObjectData *target = unloadedList->front(); - unloadedList->pop(); - - /* Free allocated memory. */ - free(target->className); - free(target); - } - - try { - list = new TClassInfoQueue(); - - /* Search delete target. */ - for (TClassMap::iterator cur = classMap->begin(); - cur != classMap->end(); ++cur) { - TObjectData *objData = (*cur).second; - - /* If class is prepared remove from class container. */ - if (unlikely(objData->isRemoved && - (atomic_get(&objData->numRefs) == 0))) { - - /* - * If we do removing map item here, - * iterator's relationship will be broken. - * So we store to list. And we remove after iterator loop. - */ - list->push(objData); - } - } - } catch(...) { - /* - * Maybe failed to allocate memory. - * E.g. raise exception at "new", "std::queue<T>::push" or etc.. - */ - delete list; - list = NULL; - } - - if (likely(list != NULL)) { - - /* Remove delete target. */ - while (!list->empty()) { - TObjectData *target = list->front(); - list->pop(); - - /* Remove from all containers. */ - removeClass(target); - - /* Free allocated memory. */ - free(target->className); - free(target); - } - } +void JNICALL + OnClassUnload(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) { + /* Get klassOop. */ + void *mirror = *(void **)klass; + void *klassOop = asKlassOop(mirror); + + if (likely(klassOop != NULL)) { + /* Search class. */ + TObjectData *counter = clsContainer->findClass(klassOop); + if (likely(counter != NULL)) { + /* + * This function will be called at safepoint and be called by VMThread + * because class unloading is single-threaded process. + * So we can lock-free access. + */ + unloadedList.insert(counter); } - /* Release class container's spin lock. */ - spinLockRelease(&lockval); - - /* Cleanup. */ - delete list; + } } +/*! + * \brief GarbageCollectionFinish JVMTI event to release memory for unloaded + * TObjectData. + * This function will be called at safepoint. + * All GC worker and JVMTI agent threads for HeapStats will not work + * at this point. + * So we can lock-free access. + */ +void JNICALL OnGarbageCollectionFinishForUnload(jvmtiEnv *jvmti) { + if (!unloadedList.empty()) { + /* Remove targets from snapshot container. */ + TSnapShotContainer::removeObjectDataFromAllSnapShots(unloadedList); + + /* Remove targets from class container. */ + for (TClassInfoSet::iterator itr = unloadedList.begin(); + itr != unloadedList.end(); itr++) { + TObjectData *objData = *itr; + clsContainer->removeClass(objData); + free(objData->className); + free(objData); + } + + /* Clear unloaded list. */ + unloadedList.clear(); + } +} +
--- a/agent/src/classContainer.hpp Thu Feb 09 12:31:27 2017 +0900 +++ b/agent/src/classContainer.hpp Mon Feb 27 19:25:26 2017 +0900 @@ -71,11 +71,6 @@ typedef std::deque<TClassContainer*> TLocalClassContainer; /*! - * \brief This type is for storing unloaded class information. - */ -typedef std::queue<TObjectData*> TClassInfoQueue; - -/*! * \brief This class is stored class information.<br> * e.g. class-name, class instance count, size, etc... */ @@ -110,12 +105,6 @@ virtual TObjectData *pushNewClass(void *klassOop, TObjectData *objData); /*! - * \brief Mark class in container to remove class. - * \param target [in] Remove class data. - */ - virtual void popClass(TObjectData *target); - - /*! * \brief Remove class from container. * \param target [in] Remove class data. */ @@ -268,15 +257,6 @@ return result; } - /*! - * \brief Commit class information changing in class container.<br> - * This function needs to prevent the crash which is related - * to class unloading. <br> - * Agent have to keep ObjectData structure(s) until dumping - * SnapShot and showing heap ranking. - */ - virtual void commitClassChange(void); - protected: /*! * \brief ClassContainer in TLS of each threads. @@ -313,11 +293,26 @@ * \brief Do we need to clear at destructor? */ bool needToClear; - - /*! - * \brief List of class information which detected unloading. - */ - TClassInfoQueue *unloadedList; }; +/*! + * \brief Class unload event. Unloaded class will be added to unloaded list. + * \param jvmti [in] JVMTI environment object. + * \param env [in] JNI environment object. + * \param thread [in] Java thread object. + * \param klass [in] Unload class object. + * \sa from: hotspot/src/share/vm/prims/jvmti.xml + */ +void JNICALL + OnClassUnload(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass); + +/*! + * \brief GarbageCollectionFinish JVMTI event to release memory for unloaded + * TObjectData. + * This function will be called at safepoint. + * All GC worker and JVMTI agent threads for HeapStats will not work + * at this point. + */ +void JNICALL OnGarbageCollectionFinishForUnload(jvmtiEnv *jvmti); + #endif // CLASS_CONTAINER_HPP
--- a/agent/src/snapShotContainer.cpp Thu Feb 09 12:31:27 2017 +0900 +++ b/agent/src/snapShotContainer.cpp Mon Feb 27 19:25:26 2017 +0900 @@ -50,6 +50,11 @@ TSnapShotQueue *TSnapShotContainer::stockQueue = NULL; /*! + * \brief Set of active TSnapShotContainer set + */ +TActiveSnapShots TSnapShotContainer::activeSnapShots; + +/*! * \brief Initialize snapshot caontainer class. * \return Is process succeed. * \warning Please call only once from main thread. @@ -100,25 +105,23 @@ TSnapShotContainer *result = NULL; ENTER_PTHREAD_SECTION(&instanceLocker) { - - if (!stockQueue->empty()) { - - /* Reuse snapshot container instance. */ - result = stockQueue->front(); - stockQueue->pop(); - } - } EXIT_PTHREAD_SECTION(&instanceLocker) - - /* If need create new instance. */ - if (result == NULL) { - + if (!stockQueue->empty()) { + /* Reuse snapshot container instance. */ + result = stockQueue->front(); + stockQueue->pop(); + } + /* If need create new instance. */ + if (result == NULL) { /* Create new snapshot container instance. */ try { - result = new TSnapShotContainer(); - } catch(...) { - result = NULL; + result = new TSnapShotContainer(); + activeSnapShots.insert(result); + } catch (...) { + result = NULL; } + } } + EXIT_PTHREAD_SECTION(&instanceLocker) return result; } @@ -164,11 +167,15 @@ } EXIT_PTHREAD_SECTION(&instanceLocker) } + ENTER_PTHREAD_SECTION(&instanceLocker) + { if (unlikely(!existStockSpace)) { - - /* Deallocate instance. */ - delete instance; + /* Deallocate instance. */ + activeSnapShots.erase(instance); + delete instance; } + } + EXIT_PTHREAD_SECTION(&instanceLocker) } /*! @@ -222,7 +229,6 @@ counter = counter->next; /* Deallocate TChildClassCounter. */ - atomic_inc(&aCounter->objData->numRefs, -1); free(aCounter->counter); free(aCounter); } @@ -350,7 +356,6 @@ : : "r" (newCounter->counter) : "cc", "memory", "%xmm0"); } - atomic_inc(&objData->numRefs, 1); newCounter->objData = objData; /* Chain children list. */ @@ -595,70 +600,24 @@ /* Loop each children class. */ TChildClassCounter *counter = srcClsCounter->child; - TChildClassCounter *prevCounter = NULL; while (counter != NULL){ TObjectData *objData = counter->objData; - /* - * If the class of objData is already unloaded, we should - * free and shold decrement reference count. - * TChildClassCounter reference count will be checked at - * TClassContainer::commitClassChange(). - */ - if (objData->isRemoved) { - atomic_inc(&objData->numRefs, -1); - TChildClassCounter *nextCounter = counter->next; - - if (prevCounter == NULL) { - srcClsCounter->child = nextCounter; - } else { - prevCounter->next = nextCounter; - } - - /* Deallocate TChildClassCounter. */ - free(counter->counter); - free(counter); - - /* Deallocate TChildClassCounter in parent container. */ - TChildClassCounter *childClsData, *parentPrevData, - *parentMorePrevData; - this->findChildCounters(clsCounter, objData->klassOop, - &childClsData, &parentPrevData, - &parentMorePrevData); - if (likely(childClsData != NULL)) { - atomic_inc(&objData->numRefs, -1); - - if (parentPrevData == NULL) { - clsCounter->child = childClsData->next; - } else { - parentPrevData->next = childClsData->next; - } - - free(childClsData->counter); - free(childClsData); - } - - counter = nextCounter; - } else { - /* Search child class. */ - TChildClassCounter *childClsData = + /* Search child class. */ + TChildClassCounter *childClsData = this->findChildClass(clsCounter, objData->klassOop); - /* Register class as child class. */ - if (unlikely(childClsData == NULL)) { - childClsData = - this->pushNewChildClass(clsCounter, objData); - } - - if (likely(childClsData != NULL)) { - /* Marge children class heap usage. */ - this->addInc(childClsData->counter, counter->counter); - } - - prevCounter = counter; - counter = counter->next; + /* Register class as child class. */ + if (unlikely(childClsData == NULL)) { + childClsData = this->pushNewChildClass(clsCounter, objData); } + if (likely(childClsData != NULL)) { + /* Marge children class heap usage. */ + this->addInc(childClsData->counter, counter->counter); + } + + counter = counter->next; } } @@ -667,3 +626,81 @@ /* Release snapshot container's spin lock. */ spinLockRelease(&lockval); } + +/*! + * \brief Remove unloaded TObjectData in this snapshot container. + * This function should be called at safepoint. + * \param unloadedList Set of unloaded TObjectData. + */ +void TSnapShotContainer::removeObjectData(TClassInfoSet &unloadedList) { + TSizeMap::iterator itr; + + /* Remove the target from parent container. */ + for (TClassInfoSet::iterator target = unloadedList.begin(); + target != unloadedList.end(); target++) { + itr = counterMap.find(*target); + if (itr != counterMap.end()) { + TClassCounter *clsCounter = itr->second; + TChildClassCounter *childCounter = clsCounter->child; + + while (childCounter != NULL) { + TChildClassCounter *nextCounter = childCounter->next; + free(childCounter->counter); + free(childCounter); + childCounter = nextCounter; + } + + free(clsCounter->counter); + free(clsCounter); + counterMap.erase(itr); + } + } + + /* Remove the target from all children in counterMap. */ + for (itr = counterMap.begin(); itr != counterMap.end(); itr++) { + TClassCounter *clsCounter = itr->second; + TChildClassCounter *childCounter = clsCounter->child; + TChildClassCounter *prevChildCounter = NULL; + + while (childCounter != NULL) { + TChildClassCounter *nextCounter = childCounter->next; + + if (unloadedList.find(childCounter->objData) != unloadedList.end()) { + free(childCounter->counter); + free(childCounter); + if (prevChildCounter == NULL) { + clsCounter->child = nextCounter; + } else { + prevChildCounter->next = nextCounter; + } + } else { + prevChildCounter = childCounter; + } + + childCounter = nextCounter; + } + } + + /* Remove the target from local containers. */ + for (TLocalSnapShotContainer::iterator container = containerMap.begin(); + container != containerMap.end(); container++) { + container->second->removeObjectData(unloadedList); + } +} + +/*! + * \brief Remove unloaded TObjectData all active snapshot container. + * \param unloadedList Set of unloaded TObjectData. + */ +void TSnapShotContainer::removeObjectDataFromAllSnapShots( + TClassInfoSet &unloadedList) { + ENTER_PTHREAD_SECTION(&instanceLocker) + { + for (TActiveSnapShots::iterator itr = activeSnapShots.begin(); + itr != activeSnapShots.end(); itr++) { + (*itr)->removeObjectData(unloadedList); + } + } + EXIT_PTHREAD_SECTION(&instanceLocker) +} +
--- a/agent/src/snapShotContainer.hpp Thu Feb 09 12:31:27 2017 +0900 +++ b/agent/src/snapShotContainer.hpp Mon Feb 27 19:25:26 2017 +0900 @@ -28,6 +28,7 @@ #include <jni.h> #include <pthread.h> #include <tr1/unordered_map> +#include <tr1/unordered_set> #include <queue> #include "util.hpp" @@ -84,12 +85,17 @@ TOopType oopType; /*!< Type of class. */ jlong clsLoaderId; /*!< Class loader instance id. */ jlong clsLoaderTag; /*!< Class loader class tag. */ - bool isRemoved; /*!< Class is already unloaded. */ jlong instanceSize; /*!< Class size if this class is instanceKlass. */ int numRefs; /*!< Number of references. */ } TObjectData; /*! + * \brief This type is for storing unloaded class information. + */ +typedef std::tr1::unordered_set<TObjectData *, + TNumericalHasher<void *> > TClassInfoSet; + +/*! * \brief This structure stored child class size information. */ struct TChildClassCounter{ @@ -159,6 +165,9 @@ typedef std::tr1::unordered_map<pthread_t, TSnapShotContainer*, TNumericalHasher<pthread_t> > TLocalSnapShotContainer; +typedef std::tr1::unordered_set<TSnapShotContainer *, + TNumericalHasher<void *> > TActiveSnapShots; + /*! * \brief This class is stored class object usage on heap. */ @@ -322,38 +331,6 @@ } /*! - * \brief Find child class and its prevous data. - * \param clsCounter [in] Parent class counter object. - * \param klassOop [in] Child class key object. - * \param counter [out] Child data - * \param prevCounter [out] previous counter of `counter` - * \param morePrevCounter [out] previous counter of `prevCounter` - */ - inline void findChildCounters(TClassCounter *clsCounter, void *klassOop, - TChildClassCounter **counter, - TChildClassCounter** prevCounter, - TChildClassCounter **morePrevCounter) { - *prevCounter = NULL; - *morePrevCounter = NULL; - *counter = clsCounter->child; - - if (*counter == NULL) { - return; - } - - /* Search children class list. */ - while ((*counter)->objData->klassOop != klassOop) { - *morePrevCounter = *prevCounter; - *prevCounter = *counter; - *counter = (*counter)->next; - - if (*counter == NULL) { - return; - } - } - }; - - /*! * \brief Find child class data. * \param clsCounter [in] Parent class counter object. * \param klassOop [in] Child class key object. @@ -366,13 +343,21 @@ TChildClassCounter *morePrevCounter = NULL; TChildClassCounter *counter = clsCounter->child; - this->findChildCounters(clsCounter, klassOop, - &counter, &prevCounter, &morePrevCounter); - if(counter == NULL){ return NULL; } + /* Search children class list. */ + while (counter->objData->klassOop != klassOop) { + morePrevCounter = prevCounter; + prevCounter = counter; + counter = counter->next; + + if (counter == NULL) { + return NULL; + } + } + /* LFU (Least Frequently Used). */ if (counter != NULL) { counter->callCount++; @@ -492,6 +477,20 @@ this->isCleared = flag; } + /*! + * \brief Remove unloaded TObjectData in this snapshot container. + * This function should be called at safepoint. + * \param unloadedList Set of unloaded TObjectData. + */ + void removeObjectData(TClassInfoSet &unloadedList); + + /*! + * \brief Remove unloaded TObjectData all active snapshot container. + * \param unloadedList Set of unloaded TObjectData. + */ + static void removeObjectDataFromAllSnapShots( + TClassInfoSet &unloadedList); + protected: /*! * \brief TSnapshotContainer constructor. @@ -560,6 +559,10 @@ */ volatile bool isCleared; + /*! + * \brief Set of active TSnapShotContainer set + */ + static TActiveSnapShots activeSnapShots; }; #endif // _SNAPSHOT_CONTAINER_HPP
--- a/agent/src/snapShotMain.cpp Thu Feb 09 12:31:27 2017 +0900 +++ b/agent/src/snapShotMain.cpp Mon Feb 27 19:25:26 2017 +0900 @@ -163,33 +163,6 @@ } /*! - * \brief Class unload event. - * \param jvmti [in] JVMTI environment object. - * \param env [in] JNI environment object. - * \param thread [in] Java thread object. - * \param klass [in] Unload class object. - * \sa from: hotspot/src/share/vm/prims/jvmti.xml - */ -void JNICALL OnClassUnload(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, - jclass klass) { - - /* Get klassOop. */ - void *mirror = *(void**)klass; - void *klassOop = asKlassOop(mirror); - - if (likely(klassOop != NULL)) { - - /* Search class. */ - TObjectData *counter = clsContainer->findClass(klassOop); - - if (likely(counter != NULL)) { - /* Remove class data. */ - clsContainer->popClass(counter); - } - } -} - -/*! * \brief Setting JVM information to snapshot. * \param snapshot [in] Snapshot instance. * \param cause [in] Cause of taking a snapshot.<br> @@ -320,6 +293,8 @@ * \param jvmti [in] JVMTI environment object. */ void JNICALL OnGarbageCollectionFinish(jvmtiEnv *jvmti) { + /* Process unloaded classes. */ + OnGarbageCollectionFinishForUnload(jvmti); /* Disable inner GC event. */ setupHookForInnerGCEvent(false, NULL); @@ -340,6 +315,9 @@ * \brief After G1 garbage collection event. */ void OnG1GarbageCollectionFinish(void) { + /* Process unloaded classes. */ + OnGarbageCollectionFinishForUnload(NULL); + //jvmInfo->loadGCCause(); jvmInfo->SetUnknownGCCause(); @@ -405,12 +383,7 @@ TObjectData *clsData = getObjectDataFromKlassOop( localClsContainer, klassOop); /* Push new child loaded class. */ - if (!clsData->isRemoved) { - clsCounter = localSnapshot->pushNewChildClass(parentCounter, clsData); - } else { - /* We should return if clsData has already been removed (unloaded). */ - return; - } + clsCounter = localSnapshot->pushNewChildClass(parentCounter, clsData); } if(unlikely(clsCounter == NULL)){ @@ -618,7 +591,9 @@ * \param jvmti [in] JVMTI environment object. */ void JNICALL OnCMSGCFinish(jvmtiEnv *jvmti) { - + /* Process unloaded classes. */ + OnGarbageCollectionFinishForUnload(jvmti); + /* Disable inner GC event. */ setupHookForInnerGCEvent(false, NULL);
--- a/agent/src/snapShotMain.hpp Thu Feb 09 12:31:27 2017 +0900 +++ b/agent/src/snapShotMain.hpp Mon Feb 27 19:25:26 2017 +0900 @@ -1,7 +1,7 @@ /*! * \file snapShotMain.hpp * \brief This file is used to take snapshot. - * Copyright (C) 2011-2013 Nippon Telegraph and Telephone Corporation + * Copyright (C) 2011-2017 Nippon Telegraph and Telephone Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -109,17 +109,6 @@ jclass klass); /*! - * \brief Class unload event. - * \param jvmti [in] JVMTI environment object. - * \param env [in] JNI environment object. - * \param thread [in] Java thread object. - * \param klass [in] Unload class object. - * \sa from: hotspot/src/share/vm/prims/jvmti.xml - */ -void JNICALL OnClassUnload(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, - jclass klass); - -/*! * \brief Before garbage collection event. * \param jvmti [in] JVMTI environment object. */
--- a/agent/src/snapShotProcessor.cpp Thu Feb 09 12:31:27 2017 +0900 +++ b/agent/src/snapShotProcessor.cpp Mon Feb 27 19:25:26 2017 +0900 @@ -1,7 +1,7 @@ /*! * \file snapShotProcessor.cpp * \brief This file is used to output ranking and call snapshot function. - * Copyright (C) 2011-2013 Nippon Telegraph and Telephone Corporation + * Copyright (C) 2011-2017 Nippon Telegraph and Telephone Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -146,7 +146,6 @@ } /* Clean up. */ - controller->_container->commitClassChange(); TSnapShotContainer::releaseInstance(snapshot); delete ranking; ranking = NULL;
--- a/agent/src/util.hpp Thu Feb 09 12:31:27 2017 +0900 +++ b/agent/src/util.hpp Mon Feb 27 19:25:26 2017 +0900 @@ -1,7 +1,7 @@ /*! * \file util.hpp * \brief This file is utilities. - * Copyright (C) 2011-2014 Nippon Telegraph and Telephone Corporation + * Copyright (C) 2011-2017 Nippon Telegraph and Telephone Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -588,25 +588,4 @@ }; }; -inline void atomic_inc(int *target, int value) { - asm volatile("lock addl %1, (%0)" : - : "r"(target), "r"(value) - : "memory", "cc"); -} - -/* - * We can use MOV operation at this point. - * LOCK'ed store operation will be occurred before load (MOV) operation. - * - * Intel (R) 64 and IA-32 Architectures Software Developer’s Manual - * Volume 3A: System Programming Guide, Part 1 - * 8.2.3.8 Locked Instructions Have a Total Order - */ -inline int atomic_get(int *target) { - register int ret; - asm volatile("movl (%1), %0" : "=r"(ret) : "r"(target) : ); - - return ret; -} - #endif