changeset 216:c0bbab76d4d1

Bug 3308: Valgrind reports some memory issues Reviewed-by: ykubota https://github.com/HeapStats/heapstats/pull/81
author Yasumasa Suenaga <yasuenag@gmail.com>
date Sun, 29 Jan 2017 21:49:16 +0900
parents ab5ab2edff59
children eff94370d9dc
files ChangeLog agent/src/heapstats-engines/classContainer.cpp agent/src/heapstats-engines/configuration.hpp agent/src/heapstats-engines/deadlockFinder.cpp agent/src/heapstats-engines/globals.hpp agent/src/heapstats-engines/libmain.cpp agent/src/heapstats-engines/logMain.cpp agent/src/heapstats-engines/logManager.cpp agent/src/heapstats-engines/overrider.cpp agent/src/heapstats-engines/snapShotMain.cpp agent/src/heapstats-engines/snapShotMain.hpp agent/src/heapstats-engines/trapSender.cpp agent/src/heapstats-engines/trapSender.hpp agent/src/heapstats-engines/util.cpp agent/test/oome/OOME.java agent/test/oome/heapstats.conf agent/test/oome/oome.supp agent/test/oome/testcase.sh agent/test/snapshot/testcase.sh
diffstat 19 files changed, 492 insertions(+), 110 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Jan 24 11:53:27 2017 +0900
+++ b/ChangeLog	Sun Jan 29 21:49:16 2017 +0900
@@ -1,3 +1,7 @@
+2017-01-29  Yasumasa Suenaga <yasuenag@gmail.com>
+
+	* Bug 3308: Valgrind reports some memory issues
+
 2017-01-24 KUBOTA Yuji <kubota.yuji@lab.ntt.co.jp>
 
 	* Bug 3296: Reference counter should manage TObjectData instance
--- a/agent/src/heapstats-engines/classContainer.cpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/classContainer.cpp	Sun Jan 29 21:49:16 2017 +0900
@@ -125,12 +125,7 @@
     }
 
     /* Create trap sender. */
-    if (conf->SnmpSend()->get()) {
-      pSender = new TTrapSender(SNMP_VERSION_2c, conf->SnmpTarget()->get(),
-                                conf->SnmpComName()->get(), 162);
-    } else {
-      pSender = NULL;
-    }
+    pSender = conf->SnmpSend()->get() ? new TTrapSender() : NULL;
 
     /* Create unloaded class information queue. */
     unloadedList = new TClassInfoQueue();
@@ -225,6 +220,8 @@
     free(cur->className);
     free(cur);
   }
+
+  atomic_inc(&result->numRefs, 1);
   return result;
 }
 
@@ -283,7 +280,6 @@
       try {
         /* Append class data. */
         (*classMap)[klassOop] = objData;
-        atomic_inc(&objData->numRefs, 1);
       } catch (...) {
         /*
          * Maybe failed to allocate memory at "std::map::operator[]".
@@ -388,9 +384,14 @@
          ++cur) {
       TObjectData *pos = (*cur).second;
 
-      if ((pos != NULL) && (atomic_get(&pos->numRefs) == 0)) {
-        free(pos->className);
-        free(pos);
+      if (likely(pos != NULL)) {
+        /* Decrement reference from this class map. */
+        atomic_inc(&pos->numRefs, -1);
+
+        if (atomic_get(&pos->numRefs) == 0) {
+          free(pos->className);
+          free(pos);
+        }
       }
     }
 
--- a/agent/src/heapstats-engines/configuration.hpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/configuration.hpp	Sun Jan 29 21:49:16 2017 +0900
@@ -1,7 +1,7 @@
 /*!
  * \file configuration.hpp
  * \brief This file treats HeapStats configuration.
- * Copyright (C) 2014-2016 Yasumasa Suenaga
+ * Copyright (C) 2014-2017 Yasumasa Suenaga
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -84,7 +84,7 @@
   /*!
    * \brief Configuration name in heapstats.conf .
    */
-  const char *configName;
+  char *configName;
 
   /*!
    * \brief Setter of this configuration.
@@ -128,6 +128,8 @@
   }
 
   virtual ~TConfigElement() {
+    free(configName);
+
     if (finalizer != NULL) {
       finalizer(value);
     }
--- a/agent/src/heapstats-engines/deadlockFinder.cpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/deadlockFinder.cpp	Sun Jan 29 21:49:16 2017 +0900
@@ -1,7 +1,7 @@
 /*!
  * \file deadlockFinder.cpp
  * \brief This file is used by find deadlock.
- * Copyright (C) 2011-2016 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
@@ -249,8 +249,7 @@
 
   try {
     /* Send resource trap. */
-    TTrapSender sender(SNMP_VERSION_2c, conf->SnmpTarget()->get(),
-                       conf->SnmpComName()->get(), 162);
+    TTrapSender sender;
 
     /* Setting sysUpTime */
     sender.setSysUpTime();
--- a/agent/src/heapstats-engines/globals.hpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/globals.hpp	Sun Jan 29 21:49:16 2017 +0900
@@ -1,7 +1,7 @@
 /*!
  * \file globals.hpp
  * \brief Definitions of global variables.
- * Copyright (C) 2015 Yasumasa Suenaga
+ * Copyright (C) 2015-2017 Yasumasa Suenaga
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -64,9 +64,6 @@
 #include "gcWatcher.hpp"
 extern TGCWatcher *gcWatcher;
 
-#include "snapShotContainer.hpp"
-extern TSnapShotContainer *snapshotByGC;
-
 /*!
  * \brief Mutex of working directory.
  */
--- a/agent/src/heapstats-engines/libmain.cpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/libmain.cpp	Sun Jan 29 21:49:16 2017 +0900
@@ -2,7 +2,7 @@
  * \file libmain.cpp
  * \brief This file is used to common works.<br>
  *        e.g. initialization, finalization, etc...
- * Copyright (C) 2011-2016 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
@@ -579,7 +579,9 @@
 
   logger->flush();
 
-  if (conf->SnmpSend()->get() && !TTrapSender::initialize()) {
+  if (conf->SnmpSend()->get() &&
+      !TTrapSender::initialize(SNMP_VERSION_2c, conf->SnmpTarget()->get(),
+                               conf->SnmpComName()->get(), 162)) {
     return SNMP_SETUP_FAILED;
   }
 
--- a/agent/src/heapstats-engines/logMain.cpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/logMain.cpp	Sun Jan 29 21:49:16 2017 +0900
@@ -206,8 +206,7 @@
 
     try {
       /* Send resource trap. */
-      TTrapSender sender(SNMP_VERSION_2c, conf->SnmpTarget()->get(),
-                         conf->SnmpComName()->get(), 162);
+      TTrapSender sender;
 
       /* Setting sysUpTime */
       sender.setSysUpTime();
--- a/agent/src/heapstats-engines/logManager.cpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/logManager.cpp	Sun Jan 29 21:49:16 2017 +0900
@@ -1,7 +1,7 @@
 /*!
  * \file logManager.cpp
  * \brief This file is used collect log information.
- * Copyright (C) 2011-2016 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
@@ -1074,8 +1074,7 @@
 
     try {
       /* Send resource trap. */
-      TTrapSender sender(SNMP_VERSION_2c, conf->SnmpTarget()->get(),
-                         conf->SnmpComName()->get(), 162);
+      TTrapSender sender;
 
       /* Setting sysUpTime */
       sender.setSysUpTime();
--- a/agent/src/heapstats-engines/overrider.cpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/overrider.cpp	Sun Jan 29 21:49:16 2017 +0900
@@ -1,7 +1,7 @@
 /*!
  * \file overrider.cpp
  * \brief Controller of overriding functions in HotSpot VM.
- * Copyright (C) 2014-2016 Yasumasa Suenaga
+ * Copyright (C) 2014-2017 Yasumasa Suenaga
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -26,6 +26,7 @@
 #include "vmVariables.hpp"
 #include "vmFunctions.hpp"
 #include "overrider.hpp"
+#include "snapShotMain.hpp"
 
 #if PROCESSOR_ARCH == X86
 #include "arch/x86/x86BitMapMarker.hpp"
@@ -1368,9 +1369,6 @@
     list = cms_sweep_hook;
     checkObjectMap->clear();
   } else if (vmVal->getUseG1()) {
-    /* If users select G1, we prepare TSnapShotContainer NOW! */
-    snapshotByGC = TSnapShotContainer::getInstance();
-
     /* Switch G1GC event hooking. */
     switchOverrideFunction(g1Event_hook, enable);
 
@@ -1727,7 +1725,7 @@
   switchOverrideFunction(g1_hook, false);
 
   /* Discard existed snapshot data */
-  snapshotByGC->clear(false);
+  clearCurrentSnapShot();
   checkObjectMap->clear();
 }
 
--- a/agent/src/heapstats-engines/snapShotMain.cpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/snapShotMain.cpp	Sun Jan 29 21:49:16 2017 +0900
@@ -758,6 +758,14 @@
         gcWatcher->stop();
       }
 
+      if (TVMVariables::getInstance()->getUseG1()) {
+        if (snapshotByGC == NULL) {
+          snapshotByGC = TSnapShotContainer::getInstance();
+        } else {
+          snapshotByGC->clear(false);
+        }
+      }
+
       /* Switch GC hooking state. */
       setGCHookState(enable);
     }
@@ -784,6 +792,13 @@
 }
 
 /*!
+ * \brief Clear current SnapShot.
+ */
+void clearCurrentSnapShot() {
+  snapshotByGC->clear(false);
+}
+
+/*!
  * \brief JVM initialization event for snapshot function.
  * \param jvmti [in] JVMTI environment object.
  * \param env   [in] JNI environment object.
@@ -844,6 +859,7 @@
   TSnapShotContainer *snapshot = popSnapShotQueue();
   /* Output all waiting snapshot. */
   while (snapshot != NULL) {
+    snapshot->setTotalSize(jvmInfo->getTotalMemory());
     notifySnapShot(snapshot);
     snapshot = popSnapShotQueue();
   }
@@ -908,16 +924,27 @@
  * \param env [in] JNI environment object.
  */
 void onAgentFinalForSnapShot(JNIEnv *env) {
+  /* Destroy SnapShot Processor instance. */
+  delete snapShotProcessor;
+  snapShotProcessor = NULL;
+
+  /*
+   * Delete snapshot instances
+   */
+  if (snapshotByCMS != NULL) {
+    TSnapShotContainer::releaseInstance(snapshotByCMS);
+  }
+  if (snapshotByGC != NULL) {
+    TSnapShotContainer::releaseInstance(snapshotByGC);
+  }
+
+  /* Finalize and deallocate old snapshot containers. */
+  TSnapShotContainer::globalFinalize();
+
   /* Destroy object that is for snapshot. */
   delete clsContainer;
   clsContainer = NULL;
 
-  delete snapShotProcessor;
-  snapShotProcessor = NULL;
-
-  /* Finalize and deallocate old snapshot containers. */
-  TSnapShotContainer::globalFinalize();
-
   /* Destroy object that is each snapshot trigger. */
   delete gcWatcher;
   gcWatcher = NULL;
--- a/agent/src/heapstats-engines/snapShotMain.hpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/snapShotMain.hpp	Sun Jan 29 21:49:16 2017 +0900
@@ -1,7 +1,7 @@
 /*!
  * \file snapShotMain.hpp
  * \brief This file is used to take snapshot.
- * Copyright (C) 2011-2015 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
@@ -58,6 +58,11 @@
 void setThreadEnableForSnapShot(jvmtiEnv *jvmti, JNIEnv *env, bool enable);
 
 /*!
+ * \brief Clear current SnapShot.
+ */
+void clearCurrentSnapShot();
+
+/*!
  * \brief JVM initialization event for snapshot function.
  * \param jvmti  [in] JVMTI environment object.
  * \param env    [in] JNI environment object.
--- a/agent/src/heapstats-engines/trapSender.cpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/trapSender.cpp	Sun Jan 29 21:49:16 2017 +0900
@@ -1,7 +1,7 @@
 /*!
  * \file trapSender.cpp
  * \brief This file is used to send SNMP trap.
- * Copyright (C) 2016 Yasumasa Suenaga
+ * Copyright (C) 2016-2017 Yasumasa Suenaga
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -40,12 +40,10 @@
  * \brief Mutex for TTrapSender.<br>
  * <br>
  * This mutex used in below process.<br>
- *   - TTrapSender::TTrapSender @ trapSender.hpp<br>
- *     To initialize SNMP trap section.<br>
- *   - TTrapSender::~TTrapSender @ trapSender.hpp<br>
- *     To finalize SNMP trap section.<br>
- *   - TTrapSender::sendTrap @ trapSender.hpp<br>
- *     To change SNMP trap section and send SNMP trap.<br>
+ *   - TTrapSender::initialize()
+ *   - TTrapSender::finalize()
+ *   - TTrapSender::~TTrapSender
+ *   - TTrapSender::sendTrap
  */
 pthread_mutex_t TTrapSender::senderMutex =
                                 PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
@@ -65,12 +63,27 @@
  */
 TNetSNMPFunctions TTrapSender::netSnmpFuncs;
 
+ /*!
+  * \brief SNMP session information.
+  */
+netsnmp_session TTrapSender::session;
+
 
 /*!
  * \brief TTrapSender initialization.
+ * \param snmp      [in] SNMP version.
+ * \param pPeer     [in] Target of SNMP trap.
+ * \param pCommName [in] Community name use for SNMP.
+ * \param port      [in] Port used by SNMP trap.
  * \return true if succeeded.
  */
-bool TTrapSender::initialize(void) {
+bool TTrapSender::initialize(int snmp, char *pPeer, char *pCommName, int port) {
+  /* If snmp target is illegal. */
+  if (pPeer == NULL) {
+    logger->printWarnMsg("Illegal SNMP target.");
+    return false;
+  }
+
   /* Get now date and set time as agent init-time. */
   struct timeval tv;
   gettimeofday(&tv, NULL);
@@ -82,6 +95,17 @@
     return false;
   }
 
+  /* Initialize session. */
+  ENTER_PTHREAD_SECTION(&senderMutex) {
+    memset(&session, 0, sizeof(netsnmp_session));
+    netSnmpFuncs.snmp_sess_init(&session);
+    session.version = snmp;
+    session.peername = strdup(pPeer);
+    session.remote_port = port;
+    session.community = (u_char *)strdup(pCommName);
+    session.community_len = (pCommName != NULL) ? strlen(pCommName) : 0;
+  } EXIT_PTHREAD_SECTION(&senderMutex)
+
   return true;
 }
 
@@ -89,6 +113,13 @@
  * \brief TTrapSender global finalization.
  */
 void TTrapSender::finalize(void) {
+  /* Close and free SNMP session. */
+  ENTER_PTHREAD_SECTION(&senderMutex) {
+    netSnmpFuncs.snmp_close(&session);
+    free(session.peername);
+    free(session.community);
+  } EXIT_PTHREAD_SECTION(&senderMutex)
+
   /* Unload library */
   if (libnetsnmp_handle != NULL) {
     dlclose(libnetsnmp_handle);
@@ -97,35 +128,15 @@
 
 /*!
  * \brief TrapSender constructor.
- * \param snmp      [in] SNMP version.
- * \param pPeer     [in] Target of SNMP trap.
- * \param pCommName [in] Community name use for SNMP.
- * \param port      [in] Port used by SNMP trap.
  */
-TTrapSender::TTrapSender(int snmp, char *pPeer, char *pCommName, int port) {
+TTrapSender::TTrapSender() {
   /* Lock to use in multi-thread. */
   ENTER_PTHREAD_SECTION(&senderMutex) {
     /* Disable NETSNMP logging. */
     netSnmpFuncs.netsnmp_register_loghandler(
                                NETSNMP_LOGHANDLER_NONE, LOG_EMERG);
-
-    /* If snmp target is illegal. */
-    if (pPeer == NULL) {
-      logger->printWarnMsg("Illegal SNMP target.");
-      pPdu = NULL;
-    } else {
-      /* Initialize session. */
-      memset(&session, 0, sizeof(netsnmp_session));
-      netSnmpFuncs.snmp_sess_init(&session);
-      session.version = snmp;
-      session.peername = strdup(pPeer);
-      session.remote_port = port;
-      session.community = (u_char *)strdup(pCommName);
-      session.community_len = (pCommName != NULL) ? strlen(pCommName) : 0;
-
-      /* Make a PDU */
-      pPdu = netSnmpFuncs.snmp_pdu_create(SNMP_MSG_TRAP2);
-    }
+    /* Make a PDU */
+    pPdu = netSnmpFuncs.snmp_pdu_create(SNMP_MSG_TRAP2);
   }
   /* Unlock to use in multi-thread. */
   EXIT_PTHREAD_SECTION(&senderMutex)
@@ -144,8 +155,7 @@
     if (pPdu != NULL) {
       netSnmpFuncs.snmp_free_pdu(pPdu);
     }
-    /* Close and free SNMP session. */
-    netSnmpFuncs.snmp_close(&session);
+
   }
   /* Unlock to use in multi-thread. */
   EXIT_PTHREAD_SECTION(&senderMutex)
@@ -278,7 +288,10 @@
     return SNMP_PROC_FAILURE;
   }
 
-  /* Send trap. */
+  /*
+   * Send trap.
+   * snmp_send() will free pPDU.
+   */
   int success = netSnmpFuncs.snmp_send(sess, pPdu);
 
   /* Clean up after send trap. */
@@ -291,6 +304,8 @@
     logger->printWarnMsg("Send SNMP trap failed!");
   }
 
+  pPdu = NULL;
+
   /* Clean up. */
   SOCK_CLEANUP;
 
@@ -306,11 +321,6 @@
  * \brief Clear PDU and allocated strings.
  */
 void TTrapSender::clearValues(void) {
-  /* If snmp target is illegal. */
-  if (pPdu == NULL) {
-    return;
-  }
-
   /* Free allocated strings. */
   std::set<char *>::iterator it = strSet.begin();
   while (it != strSet.end()) {
@@ -319,8 +329,9 @@
   }
   strSet.clear();
 
-  /* Make a PDU. */
-  pPdu = netSnmpFuncs.snmp_pdu_create(SNMP_MSG_TRAP2);
+  if (pPdu == NULL) {
+    pPdu = netSnmpFuncs.snmp_pdu_create(SNMP_MSG_TRAP2);
+  }
 }
 
 /*!
--- a/agent/src/heapstats-engines/trapSender.hpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/trapSender.hpp	Sun Jan 29 21:49:16 2017 +0900
@@ -1,7 +1,7 @@
 /*!
  * \file trapSender.hpp
  * \brief This file is used to send SNMP trap.
- * Copyright (C) 2011-2016 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
@@ -200,22 +200,18 @@
 
   /*!
    * \brief Mutex for TTrapSender.<br>
-   * <br>
-   * This mutex used in below process.<br>
-   *   - TTrapSender::TTrapSender @ trapSender.hpp<br>
-   *     To initialize SNMP trap section.<br>
-   *   - TTrapSender::~TTrapSender @ trapSender.hpp<br>
-   *     To finalize SNMP trap section.<br>
-   *   - TTrapSender::sendTrap @ trapSender.hpp<br>
-   *     To change SNMP trap section and send SNMP trap.<br>
    */
   static pthread_mutex_t senderMutex;
 
   /*!
    * \brief TTrapSender initialization.
+   * \param snmp      [in] SNMP version.
+   * \param pPeer     [in] Target of SNMP trap.
+   * \param pCommName [in] Community name use for SNMP.
+   * \param port      [in] Port used by SNMP trap.
    * \return true if succeeded.
    */
-  static bool initialize(void);
+  static bool initialize(int snmp, char *pPeer, char *pCommName, int port);
 
   /*!
    * \brief TTrapSender global finalization.
@@ -224,12 +220,8 @@
 
   /*!
    * \brief TrapSender constructor.
-   * \param snmp      [in] SNMP version.
-   * \param pPeer     [in] Target of SNMP trap.
-   * \param pCommName [in] Community name use for SNMP.
-   * \param port      [in] Port used by SNMP trap.
    */
-  TTrapSender(int snmp, char *pPeer, char *pCommName, int port);
+  TTrapSender(void);
 
   /*!
    * \brief TrapSender destructor.
@@ -299,11 +291,11 @@
    * \brief Functions in NET-SNMP client library.
    */
   static TNetSNMPFunctions netSnmpFuncs;
-
   /*!
    * \brief SNMP session information.
    */
-  netsnmp_session session;
+  static netsnmp_session session;
+
   /*!
    * \brief SNMP PDU information.
    */
--- a/agent/src/heapstats-engines/util.cpp	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/src/heapstats-engines/util.cpp	Sun Jan 29 21:49:16 2017 +0900
@@ -1,7 +1,7 @@
 /*!
  * \file util.cpp
  * \brief This file is utilities.
- * Copyright (C) 2011-2015 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
@@ -169,7 +169,14 @@
   }
 
   /* Clean up. */
-
+  for (int Cnt = 0; Cnt < count; Cnt++) {
+    jvmti->Deallocate((unsigned char *)events[Cnt].id);
+    jvmti->Deallocate((unsigned char *)events[Cnt].short_description);
+    for (int Cnt2 = 0; Cnt2 < events[Cnt].param_count; Cnt2++) {
+      jvmti->Deallocate((unsigned char *)events[Cnt].params[Cnt2].name);
+    }
+    jvmti->Deallocate((unsigned char *)events[Cnt].params);
+  }
   jvmti->Deallocate((unsigned char *)events);
   return ret;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/test/oome/OOME.java	Sun Jan 29 21:49:16 2017 +0900
@@ -0,0 +1,13 @@
+import java.util.*;
+
+
+public class OOME{
+  public static void main(String[] args){
+    List<byte[]> list = new ArrayList<>();
+
+    while(true){
+      list.add(new byte[1024*1024]);
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/test/oome/heapstats.conf	Sun Jan 29 21:49:16 2017 +0900
@@ -0,0 +1,70 @@
+# HeapStats 2.0.trunk
+# HeapStats 2.0.trunk configuration file.
+attach=true
+
+# Output file setting
+file=heapstats_snapshot.dat
+heaplogfile=heapstats_log.csv
+archivefile=heapstats_analyze.zip
+logfile=
+loglevel=INFO
+reduce_snapshot=true
+
+# SnapShot type
+collect_reftree=true
+
+# Trigger snapshot setting
+trigger_on_fullgc=true
+trigger_on_dump=true
+
+# deadlock check
+# This feature is experimental. It might be a cause of HotSpot internal error
+# when you set this flag to true.
+check_deadlock=false
+
+# Trigger logging setting
+trigger_on_logerror=true
+trigger_on_logsignal=true
+trigger_on_loglock=true
+
+# Rank setting
+rank_level=5
+rank_order=delta
+
+# Alert setting
+alert_percentage=50
+
+# Alert threshold for java heap usage.
+# "0" means disabled.
+javaheap_alert_percentage=95
+
+# Alert threshold for metaspace usage (in MB).
+# "0" means disabled.
+metaspace_alert_threshold=0
+
+# Timer setting
+snapshot_interval=0
+log_interval=300
+
+first_collect=true
+logsignal_normal=
+logsignal_all=SIGUSR2
+signal_reload=SIGHUP
+
+# Thread recording
+thread_record_enable=false
+thread_record_buffer_size=100  # Set buffer size in MB.
+thread_record_filename=heapstats-thread-records.htr
+thread_record_iotracer=/usr/local/etc/iotracer/IoTrace.class
+
+# Snmp setting
+snmp_send=true
+snmp_target=localhost
+snmp_comname=public
+# You can check library path with `net-snmp-config --netsnmp-libs`
+snmp_libpath=/usr/lib64/libnetsnmp.so
+
+logdir=./tmp
+archive_command=/usr/bin/zip %archivefile% -jr %logdir%
+
+kill_on_error=false
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/test/oome/oome.supp	Sun Jan 29 21:49:16 2017 +0900
@@ -0,0 +1,178 @@
+# According to Net-SNMP reference [1], snmp_sess_init() will allocate memory,
+# but Net-SNMP does not provide the function to release its resource.
+# So we should allow leaks about snmp_sess_init().
+#
+# [1] http://www.net-snmp.org/docs/README.thread.html
+
+
+{
+   leak-1
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:malloc
+   fun:strdup
+   obj:*
+   obj:*
+   obj:*
+   fun:_ZN11TTrapSender10initializeEiPcS0_i
+   fun:_Z20CommonInitializationP7JavaVM_PP9_jvmtiEnvPc
+   fun:Agent_OnLoad
+   fun:create_vm_init_agents
+   fun:_ZN7Threads9create_vmEP14JavaVMInitArgsPb
+   fun:JNI_CreateJavaVM
+   fun:InitializeJVM
+   fun:JavaMain
+   fun:start_thread
+}
+
+{
+   leak-2
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:calloc
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   fun:_ZN11TTrapSender10initializeEiPcS0_i
+   fun:_Z20CommonInitializationP7JavaVM_PP9_jvmtiEnvPc
+   fun:Agent_OnLoad
+   fun:create_vm_init_agents
+   fun:_ZN7Threads9create_vmEP14JavaVMInitArgsPb
+   fun:JNI_CreateJavaVM
+   fun:InitializeJVM
+   fun:JavaMain
+   fun:start_thread
+}
+
+{
+   leak-3
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:malloc
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   fun:_ZN11TTrapSender10initializeEiPcS0_i
+}
+
+{
+   leak-4
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:calloc
+   obj:*
+   obj:*
+   obj:*
+   fun:_ZN11TTrapSender10initializeEiPcS0_i
+   fun:_Z20CommonInitializationP7JavaVM_PP9_jvmtiEnvPc
+   fun:Agent_OnLoad
+   fun:create_vm_init_agents
+   fun:_ZN7Threads9create_vmEP14JavaVMInitArgsPb
+   fun:JNI_CreateJavaVM
+   fun:InitializeJVM
+   fun:JavaMain
+   fun:start_thread
+}
+
+{
+   leak-5
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:calloc
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   fun:_ZN11TTrapSender10initializeEiPcS0_i
+   fun:_Z20CommonInitializationP7JavaVM_PP9_jvmtiEnvPc
+   fun:Agent_OnLoad
+   fun:create_vm_init_agents
+   fun:_ZN7Threads9create_vmEP14JavaVMInitArgsPb
+   fun:JNI_CreateJavaVM
+   fun:InitializeJVM
+   fun:JavaMain
+}
+
+{
+   leak-6
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:calloc
+   obj:*
+   fun:_ZN11TTrapSenderC1Ev
+   fun:_ZN15TClassContainerC1EPS_b
+   fun:_Z22onAgentInitForSnapShotP9_jvmtiEnv
+   fun:_Z20CommonInitializationP7JavaVM_PP9_jvmtiEnvPc
+   fun:Agent_OnLoad
+   fun:create_vm_init_agents
+   fun:_ZN7Threads9create_vmEP14JavaVMInitArgsPb
+   fun:JNI_CreateJavaVM
+   fun:InitializeJVM
+   fun:JavaMain
+   fun:start_thread
+}
+
+{
+   leak-7
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:malloc
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   fun:_ZN11TTrapSender10initializeEiPcS0_i
+   fun:_Z20CommonInitializationP7JavaVM_PP9_jvmtiEnvPc
+}
+
+{
+   leak-7
+   Memcheck:Leak
+   match-leak-kinds: definite
+   fun:calloc
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   fun:_ZN11TTrapSender10initializeEiPcS0_i
+   fun:_Z20CommonInitializationP7JavaVM_PP9_jvmtiEnvPc
+   fun:Agent_OnLoad
+   fun:create_vm_init_agents
+   fun:_ZN7Threads9create_vmEP14JavaVMInitArgsPb
+   fun:JNI_CreateJavaVM
+}
+
+{
+   leak-8
+   Memcheck:Leak
+   match-leak-kinds: possible
+   fun:malloc
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   obj:*
+   fun:_ZN11TTrapSender10initializeEiPcS0_i
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/test/oome/testcase.sh	Sun Jan 29 21:49:16 2017 +0900
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+### Usage
+###   - Without Valgrind
+###       ./testcase.sh /path/to/heapstats
+###
+###   - With Valgrind
+###       VALGRIND_OPTION="--leak-check=yes --suppressions=/path/to/suppress" \
+###             JAVA_OPTS="<Java options (-X, -XX, ...)" \
+###                    ./testcase.sh /path/to/heapstats
+
+TARGET_HEAPSTATS=$1
+
+if [ "x$TARGET_HEAPSTATS" = "x" ]; then
+  echo "You must set HeapStats agent that you want to check."
+  exit 1
+fi
+
+if [ "x$JAVA_HOME" = "x" ]; then
+  JAVA_HOME=/usr/lib/jvm/java-openjdk
+fi
+
+EXEC_COMMAND="$JAVA_HOME/bin/java -Xmx500m $JAVA_OPTS"
+
+if [ -n "$VALGRIND_OPTION" ]; then
+  EXEC_COMMAND="valgrind $VALGRIND_OPTION $EXEC_COMMAND"
+fi
+
+EXEC_COMMAND="$EXEC_COMMAND -agentpath:$TARGET_HEAPSTATS"
+
+# Check1: Parallel
+echo "Check1-1: Parallel"
+$EXEC_COMMAND -XX:+UseParallelGC -XX:-UseParallelOldGC OOME
+echo "Check1-2: Parallel (-UseCOOP)"
+$EXEC_COMMAND -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:-UseCompressedOops OOME
+
+# Check2: ParallelOld
+echo "Check2-1: ParallelOld"
+$EXEC_COMMAND -XX:+UseParallelOldGC OOME
+echo "Check2-2: ParallelOld (-UseCOOP)"
+$EXEC_COMMAND -XX:+UseParallelOldGC -XX:-UseCompressedOops OOME
+
+# Check3: CMS
+echo "Check3-1: CMS"
+$EXEC_COMMAND -XX:+UseConcMarkSweepGC OOME
+echo "Check3-2: CMS (-UseCOOP)"
+$EXEC_COMMAND -XX:+UseConcMarkSweepGC -XX:-UseCompressedOops OOME
+echo "Check3-3: CMS (+ExplicitGC)"
+$EXEC_COMMAND -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent OOME
+echo "Check3-4: CMS (+ExplicitGC -UseCOOP)"
+$EXEC_COMMAND -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:-UseCompressedOops OOME
+
+# Check4: G1
+echo "Check4-1: G1"
+$EXEC_COMMAND -XX:+UseG1GC OOME
+echo "Check4-2: G1 (-UseCOOP)"
+$EXEC_COMMAND -XX:+UseG1GC -XX:-UseCompressedOops OOME
+echo "Check4-3: G1 (+ExplicitGC)"
+$EXEC_COMMAND -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent OOME
+echo "Check4-4: G1 (+ExplicitGC -UseCOOP)"
+$EXEC_COMMAND -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:-UseCompressedOops OOME
+
--- a/agent/test/snapshot/testcase.sh	Tue Jan 24 11:53:27 2017 +0900
+++ b/agent/test/snapshot/testcase.sh	Sun Jan 29 21:49:16 2017 +0900
@@ -1,5 +1,14 @@
 #!/bin/bash
 
+### Usage
+###   - Without Valgrind
+###       ./testcase.sh /path/to/heapstats
+###
+###   - With Valgrind
+###       VALGRIND_OPTION="--leak-check=yes --suppressions=/path/to/suppress" \
+###             JAVA_OPTS="<Java options (-X, -XX, ...)" \
+###                    ./testcase.sh /path/to/heapstats
+
 TARGET_HEAPSTATS=$1
 
 if [ "x$TARGET_HEAPSTATS" = "x" ]; then
@@ -11,36 +20,43 @@
   JAVA_HOME=/usr/lib/jvm/java-openjdk
 fi
 
+EXEC_COMMAND="$JAVA_HOME/bin/java $JAVA_OPTS"
+
+if [ -n "$VALGRIND_OPTION" ]; then
+  EXEC_COMMAND="valgrind $VALGRIND_OPTION $EXEC_COMMAND"
+fi
+
+EXEC_COMMAND="$EXEC_COMMAND -agentpath:$TARGET_HEAPSTATS"
 
 # Check1: Parallel
 echo "Check1-1: Parallel"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseParallelGC -XX:-UseParallelOldGC Simple
+$EXEC_COMMAND -XX:+UseParallelGC -XX:-UseParallelOldGC Simple
 echo "Check1-2: Parallel (-UseCOOP)"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:-UseCompressedOops Simple
+$EXEC_COMMAND -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:-UseCompressedOops Simple
 
 # Check2: ParallelOld
 echo "Check2-1: ParallelOld"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseParallelOldGC Simple
+$EXEC_COMMAND -XX:+UseParallelOldGC Simple
 echo "Check2-2: ParallelOld (-UseCOOP)"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseParallelOldGC -XX:-UseCompressedOops Simple
+$EXEC_COMMAND -XX:+UseParallelOldGC -XX:-UseCompressedOops Simple
 
 # Check3: CMS
 echo "Check3-1: CMS"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseConcMarkSweepGC Simple
+$EXEC_COMMAND -XX:+UseConcMarkSweepGC Simple
 echo "Check3-2: CMS (-UseCOOP)"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseConcMarkSweepGC -XX:-UseCompressedOops Simple
+$EXEC_COMMAND -XX:+UseConcMarkSweepGC -XX:-UseCompressedOops Simple
 echo "Check3-3: CMS (+ExplicitGC)"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent Simple
+$EXEC_COMMAND -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent Simple
 echo "Check3-4: CMS (+ExplicitGC -UseCOOP)"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:-UseCompressedOops Simple
+$EXEC_COMMAND -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:-UseCompressedOops Simple
 
 # Check4: G1
 echo "Check4-1: G1"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseG1GC Simple
+$EXEC_COMMAND -XX:+UseG1GC Simple
 echo "Check4-2: G1 (-UseCOOP)"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseG1GC -XX:-UseCompressedOops Simple
+$EXEC_COMMAND -XX:+UseG1GC -XX:-UseCompressedOops Simple
 echo "Check4-3: G1 (+ExplicitGC)"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent Simple
+$EXEC_COMMAND -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent Simple
 echo "Check4-4: G1 (+ExplicitGC -UseCOOP)"
-$JAVA_HOME/bin/java -agentpath:$TARGET_HEAPSTATS $JAVA_OPTS -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:-UseCompressedOops Simple
+$EXEC_COMMAND -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:-UseCompressedOops Simple