Mercurial > hg > release > heapstats-1.1
view agent/src/classContainer.hpp @ 42:6dd54555d3bb
Bug 2378: JVM may crashe when class unload is occurred.
reviewed-by: ykubota
author | Yasumasa Suenaga <yasuenag@gmail.com> |
---|---|
date | Sun, 24 May 2015 18:32:48 +0900 |
parents | b21d5eef58f0 |
children | ef928edf1d20 |
line wrap: on
line source
/*! * \file classContainer.hpp * \brief This file is used to add up using size every class. * Copyright (C) 2011-2015 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 * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef CLASS_CONTAINER_HPP #define CLASS_CONTAINER_HPP #include <limits.h> #include <sys/time.h> #include <string.h> #include <jni.h> #include <pthread.h> #include <tr1/unordered_map> #include <deque> #include "util.hpp" #include "trapSender.hpp" #include "jvmInfo.hpp" #include "sorter.hpp" #include "snapShotContainer.hpp" /*! * \brief This structure stored size of a class used in heap. */ typedef struct{ jlong tag; /*!< Pointer of TObjectData. */ jlong usage; /*!< Class using total size. */ jlong delta; /*!< Class delta size from before snapshot. */ } THeapDelta; /*! * \brief This type is for map stored class information. */ typedef std::tr1::unordered_map<void*, TObjectData*, TNumericalHasher<void*> > TClassMap; /*! * \brief Memory usage alert types. */ typedef enum{ ALERT_JAVA_HEAP, ALERT_METASPACE } TMemoryUsageAlertType; /*! * \brief This class is stored class information.<br> * e.g. class-name, class instance count, size, etc... */ class TClassContainer; /*! * \brief This type is for TClassContainer in Thread-Local-Storage. */ 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... */ class TClassContainer { public: /*! * \brief TClassContainer constructor. * \param base [in] Parent class container instance. * \param needToClr [in] Flag of deallocate all data on destructor. */ TClassContainer(TClassContainer *base = NULL, bool needToClr = true); /*! * \brief TClassContainer destructor. */ virtual ~TClassContainer(void); /*! * \brief Append new-class to container. * \param klassOop [in] New class oop. * \return New-class data. */ virtual TObjectData *pushNewClass(void *klassOop); /*! * \brief Append new-class to container. * \param klassOop [in] New class oop. * \param objData [in] Add new class data. * \return New-class data.<br /> * This value isn't equal param "objData", * if already registered equivalence class. */ 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. */ virtual void removeClass(TObjectData *target); /*! * \brief Search class from container. * \param klassOop [in] Target class oop. * \return Class data of target class. */ inline TObjectData *findClass(void *klassOop) { /* Search class data. */ TObjectData *result = NULL; /* Get class container's spin lock. */ spinLockWait(&lockval); { /* Search class data. */ TClassMap::iterator it = classMap->find(klassOop); if (it != classMap->end()) { result = (*it).second; } } /* Release class container's spin lock. */ spinLockRelease(&lockval); return result; } /*! * \brief Search class from container without container lock. * \param klassOop [in] Target class oop. * \return Class data of target class. */ inline TObjectData *findClassWithoutLock(void *klassOop) { TClassMap::iterator it = classMap->find(klassOop); return (it != classMap->end()) ? it->second : NULL; } /*! * \brief Update class oop. * \param oldKlassOop [in] Target old class oop. * \param newKlassOop [in] Target new class oop. * \return Class data of target class. */ inline void updateClass(void *oldKlassOop, void *newKlassOop) { /* Get class container's spin lock. */ spinLockWait(&lockval); { /* Search class data. */ TClassMap::iterator it = classMap->find(oldKlassOop); if (it != classMap->end()) { TObjectData *cur = (*it).second; /* Remove old klassOop. */ classMap->erase(it); try { /* Update class data. */ (*classMap)[newKlassOop] = cur; cur->klassOop = newKlassOop; } catch(...) { /* * Maybe failed to allocate memory * at "std::map::operator[]". */ } } } /* Release class container's spin lock. */ spinLockRelease(&lockval); /* Get spin lock of containers queue. */ spinLockWait(&queueLock); { TLocalClassContainer::iterator it = localContainers.begin(); /* Broadcast to each local container. */ for (; it != localContainers.end(); it++) { (*it)->updateClass(oldKlassOop, newKlassOop); } } /* Release spin lock of containers queue. */ spinLockRelease(&queueLock); } /*! * \brief Get class entries count. * \return Entries count of class information. */ inline size_t getContainerSize(void) { size_t result = 0; /* Get class container's spin lock. */ spinLockWait(&lockval); { result = this->classMap->size(); } /* Release class container's spin lock. */ spinLockRelease(&lockval); return result; } /*! * \brief Remove all-class from container. */ virtual void allClear(void); /*! * \brief Output all-class information to file. * \param snapshot [in] Snapshot instance. * \param rank [out] Sorted-class information. * \return Value is zero, if process is succeed.<br /> * Value is error number a.k.a. "errno", if process is failure. */ virtual int afterTakeSnapShot(TSnapShotContainer *snapshot, TSorter<THeapDelta> **rank); /*! * \brief Get local class container with each threads. * \return Local class container instance for this thread. */ inline TClassContainer *getLocalContainer(void) { /* Get container for this thread. */ TClassContainer *result = (TClassContainer *)pthread_getspecific(clsContainerKey); /* If container isn't exists yet. */ if (unlikely(result == NULL)) { try { result = new TClassContainer(this, false); } catch(...) { /* Maybe raised badalloc exception. */ return NULL; } pthread_setspecific(clsContainerKey, result); bool isFailure = false; /* Get spin lock of containers queue. */ spinLockWait(&queueLock); { try { localContainers.push_back(result); } catch(...) { /* Maybe failed to add queue. */ isFailure = true; } } /* Release spin lock of containers queue. */ spinLockRelease(&queueLock); if (unlikely(isFailure)) { delete result; result = NULL; } } 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. */ TLocalClassContainer localContainers; RELEASE_ONLY(private:) /*! * \brief SNMP trap sender. */ TTrapSender *pSender; /*! * \brief Maps of class counting record. */ TClassMap *classMap; /*! * \brief The thread storage key for each local class container. */ pthread_key_t clsContainerKey; /*! * \brief SpinLock variable for class container instance. */ volatile int lockval; /*! * \brief SpinLock variable for queue of local class containers. */ volatile int queueLock; /*! * \brief Do we need to clear at destructor? */ bool needToClear; /*! * \brief List of class information which detected unloading. */ TClassInfoQueue *unloadedList; }; #endif // CLASS_CONTAINER_HPP