changeset 258:9a13d070bb77

Bug 3511: Migrate to Intel TBB Reviewed-by: ykubota https://github.com/HeapStats/heapstats/pull/128
author Yasumasa Suenaga <yasuenag@gmail.com>
date Fri, 19 Jan 2018 14:06:27 +0900
parents bec923d3aeb6
children 07a69089c840
files ChangeLog INSTALL Makefile.in aclocal.m4 agent/Makefile.in agent/attacher/Makefile.in agent/src/Makefile.in agent/src/heapstats-engines/Makefile.in agent/src/heapstats-engines/classContainer.cpp agent/src/heapstats-engines/classContainer.hpp agent/src/heapstats-engines/libmain.cpp agent/src/heapstats-engines/snapShotContainer.cpp agent/src/heapstats-engines/snapShotContainer.hpp agent/src/heapstats-engines/snapShotMain.cpp agent/src/heapstats-engines/snapShotProcessor.cpp agent/src/heapstats-engines/threadRecorder.cpp agent/src/heapstats-engines/threadRecorder.hpp agent/src/heapstats-engines/util.hpp agent/src/iotracer/Makefile.in configure configure.ac mbean/Makefile.in mbean/native/Makefile.in specs/heapstats.spec
diffstat 24 files changed, 473 insertions(+), 985 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Dec 05 16:18:49 2017 +0900
+++ b/ChangeLog	Fri Jan 19 14:06:27 2018 +0900
@@ -1,3 +1,7 @@
+2018-01-19 Yasumasa Suenaga <yasuenag@gmail.com>
+
+	* Bug 3511: Migrate to Intel TBB
+
 2017-12-05 Yasumasa Suenaga <yasuenag@gmail.com>
 
 	* Bug 3498: Agent cannot work on brandnew glibc
--- a/INSTALL	Tue Dec 05 16:18:49 2017 +0900
+++ b/INSTALL	Fri Jan 19 14:06:27 2018 +0900
@@ -11,6 +11,9 @@
     - pcre-devel 6 or later
     - net-snmp-devel 5.3 or later
     - binutils 2 or later
+    - Intel(R) Threading Building Blocks (TBB)
+        * If you compile the agent for Raspberry Pi 2, you have to install
+          libtbb2 and libtbb-dev in official Debian repository.
 
   Analyzer:
     - Java SE 8 or later
--- a/Makefile.in	Tue Dec 05 16:18:49 2017 +0900
+++ b/Makefile.in	Fri Jan 19 14:06:27 2018 +0900
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
--- a/aclocal.m4	Tue Dec 05 16:18:49 2017 +0900
+++ b/aclocal.m4	Fri Jan 19 14:06:27 2018 +0900
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -20,7 +20,7 @@
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically 'autoreconf'.])])
 
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -35,7 +35,7 @@
 [am__api_version='1.15'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.15], [],
+m4_if([$1], [1.15.1], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -51,14 +51,14 @@
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.15])dnl
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
 # Figure out how to run the assembler.                      -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -78,7 +78,7 @@
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -130,7 +130,7 @@
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -161,7 +161,7 @@
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -352,7 +352,7 @@
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -428,7 +428,7 @@
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -625,7 +625,7 @@
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -646,7 +646,7 @@
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -668,7 +668,7 @@
 # Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
 # From Jim Meyering
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -703,7 +703,7 @@
 
 # Check to see how 'make' treats includes.	            -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -753,7 +753,7 @@
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -792,7 +792,7 @@
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -821,7 +821,7 @@
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -868,7 +868,7 @@
 # For backward compatibility.
 AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -887,7 +887,7 @@
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -968,7 +968,7 @@
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1028,7 +1028,7 @@
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1056,7 +1056,7 @@
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1075,7 +1075,7 @@
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
--- a/agent/Makefile.in	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/Makefile.in	Fri Jan 19 14:06:27 2018 +0900
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
--- a/agent/attacher/Makefile.in	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/attacher/Makefile.in	Fri Jan 19 14:06:27 2018 +0900
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
--- a/agent/src/Makefile.in	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/Makefile.in	Fri Jan 19 14:06:27 2018 +0900
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
--- a/agent/src/heapstats-engines/Makefile.in	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/Makefile.in	Fri Jan 19 14:06:27 2018 +0900
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
--- a/agent/src/heapstats-engines/classContainer.cpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/classContainer.cpp	Fri Jan 19 14:06:27 2018 +0900
@@ -78,7 +78,6 @@
 static char ORDER_USAGE[6] = "USAGE";
 
 static TClassInfoSet unloadedList;
-volatile int unloadedList_lock = 0;
 
 /*!
  * \briefString of DELTA order.
@@ -87,81 +86,21 @@
 
 /*!
  * \brief TClassContainer constructor.
- * \param base      [in] Parent class container instance.
- * \param needToClr [in] Flag of deallocate all data on destructor.
  */
-TClassContainer::TClassContainer(TClassContainer *base, bool needToClr)
-    : localContainers() {
-  /* Initialize each field. */
-  lockval = 0;
-  queueLock = 0;
-  needToClear = needToClr;
-  classMap = NULL;
-  pSender = NULL;
-
-  if (likely(base != NULL)) {
-    /* Get parent container's spin lock. */
-    spinLockWait(&base->lockval);
-  }
-
-  try {
-    if (unlikely(base == NULL)) {
-      classMap = new TClassMap();
-    } else {
-      classMap = new TClassMap(*base->classMap);
-    }
-  } catch (...) {
-    /*
-     * This statement is for release lock. So allocate check is after.
-     */
-  }
-
-  if (likely(base != NULL)) {
-    /* Release parent container's spin lock. */
-    spinLockRelease(&base->lockval);
-  }
-
-  try {
-    /* Check classMap. */
-    if (unlikely(classMap == NULL)) {
-      throw 1;
-    }
-
-    /* Create trap sender. */
-    pSender = conf->SnmpSend()->get() ? new TTrapSender() : NULL;
-
-    /* Create thread storage key. */
-    if (unlikely(pthread_key_create(&clsContainerKey, NULL) != 0)) {
-      throw 1;
-    }
-  } catch (...) {
-    delete classMap;
-    delete pSender;
-    throw "TClassContainer initialize failed!";
-  }
+TClassContainer::TClassContainer(void) : classMap(), updatedClassList() {
+  /* Create trap sender. */
+  pSender = conf->SnmpSend()->get() ? new TTrapSender() : NULL;
 }
 
 /*!
  * \brief TClassContainer destructor.
  */
 TClassContainer::~TClassContainer(void) {
-  if (needToClear) {
-    /* Cleanup class information. */
-    this->allClear();
-  }
-
-  /* Cleanup ClassContainer in TLS. */
-  for (TLocalClassContainer::iterator it = localContainers.begin();
-       it != localContainers.end(); it++) {
-    delete *it;
-  }
+  /* Cleanup class information. */
+  this->allClear();
 
   /* Cleanup instances. */
-  delete classMap;
   delete pSender;
-
-  /* Cleanup thread storage key. */
-  pthread_key_delete(clsContainerKey);
 }
 
 /*!
@@ -231,70 +170,26 @@
  */
 TObjectData *TClassContainer::pushNewClass(void *klassOop,
                                            TObjectData *objData) {
-  TObjectData *existData = NULL;
-  /* Get class container's spin lock. */
-  spinLockWait(&lockval);
-  {
-    /*
-     * Jvmti extension event "classUnload" is loose once in a while.
-     * The event forget callback occasionally when class unloading.
-     * So we need to check klassOop that was doubling.
-     */
-
-    /* Check klassOop doubling. */
-    TClassMap::iterator it = classMap->find(klassOop);
-    if (likely(it != classMap->end())) {
-      /* Store data to return value as result. */
-      TObjectData *expectData = (*it).second;
-      if (likely(expectData != NULL)) {
-        /* If adding class data is already exists. */
-        if (unlikely(expectData->className != NULL &&
-                     strcmp(objData->className, expectData->className) == 0 &&
-                     objData->clsLoaderId == expectData->clsLoaderId)) {
-          /* Return existing data on map. */
-          existData = expectData;
-        } else {
-          /* klass oop is doubling for another class. */
-          spinLockWait(&unloadedList_lock);
-          {
-            unloadedList.insert(expectData);
-          }
-          spinLockRelease(&unloadedList_lock);
-        }
-      }
-    }
-
-    if (likely(existData == NULL)) {
-      try {
-        /* Append class data. */
-        (*classMap)[klassOop] = objData;
-      } catch (...) {
-        /*
-         * Maybe failed to allocate memory at "std::map::operator[]".
-         */
+  /*
+   * Jvmti extension event "classUnload" is loose once in a while.
+   * The event forget callback occasionally when class unloading.
+   * So we need to check klassOop that was doubling.
+   */
+  TClassMap::accessor acc;
+  if (!classMap.insert(acc, std::make_pair(klassOop, objData))) {
+    TObjectData *expectData = acc->second;
+    if (likely(expectData != NULL)) {
+      /* If adding class data for another class is already exists. */
+      if (unlikely((expectData->className == NULL) ||
+                   (strcmp(objData->className, expectData->className) != 0) ||
+                   (objData->clsLoaderId != expectData->clsLoaderId))) {
+        acc->second = objData;
+        unloadedList.push(expectData);
       }
     }
   }
-  /* Release class container's spin lock. */
-  spinLockRelease(&lockval);
 
-  /* If already exist class data. */
-  if (unlikely(existData != NULL)) {
-    return existData;
-  }
-
-  /* Get spin lock of containers queue. */
-  spinLockWait(&queueLock);
-  {
-    /* Broadcast to each local container. */
-    for (TLocalClassContainer::iterator it = localContainers.begin();
-         it != localContainers.end(); it++) {
-      (*it)->pushNewClass(klassOop, objData);
-    }
-  }
-  /* Release spin lock of containers queue. */
-  spinLockRelease(&queueLock);
-  return objData;
+  return acc->second;
 }
 
 /*!
@@ -302,43 +197,19 @@
  * \param target [in] Remove class data.
  */
 void TClassContainer::removeClass(TObjectData *target) {
-  /* Remove item from map. Please callee has container's lock. */
-  classMap->erase(target->klassOop);
-
-  /* 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->erase(target->klassOop); }
-      /* Release local container's spin lock. */
-      spinLockRelease(&(*it)->lockval);
-    }
-  }
-  /* Release spin lock of containers queue. */
-  spinLockRelease(&queueLock);
+  classMap.erase(target->klassOop);
 }
 
 /*!
  * \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) {
-  /* Add all TObjectData pointers in parent container map to unloadedList */
-  for (TClassMap::iterator cur = classMap->begin(); cur != classMap->end();
-       ++cur) {
-    unloadedList.insert(cur->second);
-  }
-
-  /* Release all memory for TObjectData. */
-  for (TClassInfoSet::iterator itr = unloadedList.begin();
-       itr != unloadedList.end(); itr++) {
-    free((*itr)->className);
-    free(*itr);
+  /* Add all TObjectData pointers in container map to unloadedList */
+  for (auto cur = classMap.begin(); cur != classMap.end(); cur++) {
+    TObjectData *objData = cur->second;
+    free(objData->className);
+    free(objData);
   }
 }
 
@@ -566,11 +437,12 @@
  * \param fd      [in] Target file descriptor.
  * \param objData [in] The class information.
  * \param cur     [in] The class size counter.
+ * \param snapshot[in] SnapShot container.
  * \return Value is zero, if process is succeed.<br />
  *         Value is error number a.k.a. "errno", if process is failure.
  */
 inline int writeClassData(const int fd, const TObjectData *objData,
-                          const TClassCounter *cur) {
+                          TClassCounter *cur, TSnapShotContainer *snapshot) {
   int result = 0;
   /* Output class-information. */
   try {
@@ -700,27 +572,10 @@
   }
 
   /* Class map used snapshot output. */
-  TClassMap *workClsMap = NULL;
-  /* Get class container's spin lock. */
-  spinLockWait(&lockval);
-  {
-    try {
-      workClsMap = new TClassMap(*this->classMap);
-    } catch (...) {
-      workClsMap = NULL;
-    }
-  }
-  /* Release class container's spin lock. */
-  spinLockRelease(&lockval);
-
-  if (unlikely(workClsMap == NULL)) {
-    int raisedErrNum = errno;
-    logger->printWarnMsgWithErrno("Couldn't allocate working memory!");
-    return raisedErrNum;
-  }
+  auto workClsMap(classMap);
 
   /* Allocate return array. */
-  jlong rankCnt = workClsMap->size();
+  jlong rankCnt = workClsMap.size();
   rankCnt =
       (rankCnt < conf->RankLevel()->get()) ? rankCnt : conf->RankLevel()->get();
 
@@ -734,7 +589,6 @@
   } catch (...) {
     int raisedErrNum = errno;
     logger->printWarnMsgWithErrno("Couldn't allocate working memory!");
-    delete workClsMap;
     return raisedErrNum;
   }
 
@@ -746,7 +600,6 @@
     int raisedErrNum = errno;
     logger->printWarnMsgWithErrno("Could not open %s", conf->FileName()->get());
     delete sortArray;
-    delete workClsMap;
     return raisedErrNum;
   }
 
@@ -770,7 +623,6 @@
     logger->printWarnMsg("Could not write snapshot");
     close(fd);
     delete sortArray;
-    delete workClsMap;
     return raisedErrNum;
   }
 
@@ -782,9 +634,8 @@
   register jlong AlertThreshold = conf->getAlertThreshold();
 
   /* Loop each class. */
-  for (TClassMap::iterator it = workClsMap->begin(); it != workClsMap->end();
-       ++it) {
-    TObjectData *objData = (*it).second;
+  for (auto it = workClsMap.begin(); it != workClsMap.end(); it++) {
+    TObjectData *objData = it->second;
     TClassCounter *cur = snapshot->findClass(objData);
     /* If don't registed class yet. */
     if (unlikely(cur == NULL)) {
@@ -808,7 +659,7 @@
     if (!conf->ReduceSnapShot()->get() || (result.usage > 0)) {
       /* Output class-information. */
       if (likely(raiseErrorCode == 0)) {
-        raiseErrorCode = writeClassData(fd, objData, cur);
+        raiseErrorCode = writeClassData(fd, objData, cur, snapshot);
       }
 
       numEntries++;
@@ -848,7 +699,6 @@
       }
     }
   }
-  delete workClsMap;
 
   /* Set output entry count. */
   hdr.size = numEntries;
@@ -923,7 +773,7 @@
        * because class unloading is single-threaded process.
        * So we can lock-free access.
        */
-      unloadedList.insert(counter);
+      unloadedList.push(counter);
     }
   }
 }
@@ -942,16 +792,15 @@
     TSnapShotContainer::removeObjectDataFromAllSnapShots(unloadedList);
 
     /* Remove targets from class container. */
-    for (TClassInfoSet::iterator itr = unloadedList.begin();
-         itr != unloadedList.end(); itr++) {
-      TObjectData *objData = *itr;
+    TObjectData *objData;
+    while (unloadedList.try_pop(objData)) {
       clsContainer->removeClass(objData);
       free(objData->className);
       free(objData);
     }
+  }
 
-    /* Clear unloaded list. */
-    unloadedList.clear();
-  }
+  /* Clear updated data */
+  clsContainer->removeBeforeUpdatedData();
 }
 
--- a/agent/src/heapstats-engines/classContainer.hpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/classContainer.hpp	Fri Jan 19 14:06:27 2018 +0900
@@ -22,12 +22,13 @@
 #ifndef CLASS_CONTAINER_HPP
 #define CLASS_CONTAINER_HPP
 
-#include <tr1/unordered_map>
-#include <deque>
+#include <tbb/concurrent_hash_map.h>
+#include <tbb/concurrent_queue.h>
+#include <algorithm>
 
-#include "snapShotContainer.hpp"
 #include "sorter.hpp"
 #include "trapSender.hpp"
+#include "oopUtil.hpp"
 
 #if PROCESSOR_ARCH == X86
 #include "arch/x86/lock.inline.hpp"
@@ -36,6 +37,31 @@
 #endif
 
 /*!
+ * \brief Pointer type of klassOop.
+ */
+typedef void* PKlassOop;
+
+/*!
+ * \brief Forward declaration in snapShotContainer.hpp
+ */
+class TSnapShotContainer;
+
+/*!
+ * \brief This structure stored class information.
+ */
+typedef struct {
+  jlong tag;          /*!< Class tag.                                 */
+  jlong classNameLen; /*!< Class name.                                */
+  char *className;    /*!< Class name length.                         */
+  PKlassOop klassOop; /*!< Java inner class object.                   */
+  jlong oldTotalSize; /*!< Class old total use size.                  */
+  TOopType oopType;   /*!< Type of class.                             */
+  jlong clsLoaderId;  /*!< Class loader instance id.                  */
+  jlong clsLoaderTag; /*!< Class loader class tag.                    */
+  jlong instanceSize; /*!< Class size if this class is instanceKlass. */
+} TObjectData;
+
+/*!
  * \brief This structure stored size of a class used in heap.
  */
 typedef struct {
@@ -45,27 +71,20 @@
 } 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...
+ * \brief Type is for unloaded class information.
  */
-class TClassContainer;
+typedef tbb::concurrent_queue<TObjectData *> TClassInfoSet;
 
 /*!
- * \brief This type is for TClassContainer in Thread-Local-Storage.
+ * \brief Type is for storing class information.
  */
-typedef std::deque<TClassContainer *> TLocalClassContainer;
-
+typedef tbb::concurrent_hash_map<PKlassOop, TObjectData *,
+                                 TPointerHasher<PKlassOop> > TClassMap;
 /*!
  * \brief This class is stored class information.<br>
  *        e.g. class-name, class instance count, size, etc...
@@ -74,10 +93,8 @@
  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);
+  TClassContainer(void);
   /*!
    * \brief TClassContainer destructor.
    */
@@ -88,7 +105,7 @@
    * \param klassOop [in] New class oop.
    * \return New-class data.
    */
-  virtual TObjectData *pushNewClass(void *klassOop);
+  virtual TObjectData *pushNewClass(PKlassOop klassOop);
 
   /*!
    * \brief Append new-class to container.
@@ -98,7 +115,7 @@
    *         This value isn't equal param "objData",
    *         if already registered equivalence class.
    */
-  virtual TObjectData *pushNewClass(void *klassOop, TObjectData *objData);
+  virtual TObjectData *pushNewClass(PKlassOop klassOop, TObjectData *objData);
 
   /*!
    * \brief Remove class from container.
@@ -111,23 +128,9 @@
    * \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;
+  inline TObjectData *findClass(PKlassOop klassOop) {
+    TClassMap::const_accessor acc;
+    return classMap.find(acc, klassOop) ? acc->second : NULL;
   }
 
   /*!
@@ -136,44 +139,20 @@
    * \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);
+  inline void updateClass(PKlassOop oldKlassOop, PKlassOop newKlassOop) {
+    TClassMap::const_accessor acc;
+    if (classMap.find(acc, oldKlassOop)) {
+      TObjectData *cur = acc->second;
+      acc.release();
 
-        try {
-          /* Update class data. */
-          (*classMap)[newKlassOop] = cur;
-          cur->klassOop = newKlassOop;
-        } catch (...) {
-          /*
-           * Maybe failed to allocate memory
-           * at "std::map::operator[]".
-           */
-        }
-      }
+      cur->klassOop = newKlassOop;
+      TClassMap::accessor new_acc;
+      classMap.insert(new_acc, std::make_pair(newKlassOop, cur));
+      new_acc.release();
+
+      classMap.erase(oldKlassOop);
+      updatedClassList.push(oldKlassOop);
     }
-    /* 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);
   }
 
   /*!
@@ -181,14 +160,7 @@
    * \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;
+    return classMap.size();
   }
 
   /*!
@@ -205,55 +177,14 @@
   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;
-      }
+  void removeBeforeUpdatedData(void) {
+    PKlassOop klass;
+    while (updatedClassList.try_pop(klass)) {
+      classMap.erase(klass);
     }
-
-    return result;
   }
 
- protected:
-  /*!
-   * \brief ClassContainer in TLS of each threads.
-   */
-  TLocalClassContainer localContainers;
-
-  RELEASE_ONLY(private :)
+ private:
   /*!
    * \brief SNMP trap sender.
    */
@@ -262,27 +193,12 @@
   /*!
    * \brief Maps of class counting record.
    */
-  TClassMap *classMap;
-
-  /*!
-   * \brief The thread storage key for each local class container.
-   */
-  pthread_key_t clsContainerKey;
+  TClassMap classMap;
 
   /*!
-   * \brief SpinLock variable for class container instance.
-   */
-  volatile int lockval;
-
-  /*!
-   * \brief SpinLock variable for queue of local class containers.
+   * \brief Updated class list.
    */
-  volatile int queueLock;
-
-  /*!
-   * \brief Do we need to clear at destructor?
-   */
-  bool needToClear;
+  tbb::concurrent_queue<PKlassOop> updatedClassList;
 };
 
 /*!
--- a/agent/src/heapstats-engines/libmain.cpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/libmain.cpp	Fri Jan 19 14:06:27 2018 +0900
@@ -454,6 +454,7 @@
   TThreadRecorder::setCapabilities(&capabilities);
 
   /* Setup GarbageCollectionFinish callback for class unloading. */
+  TGarbageCollectionFinishCallback::mergeCapabilities(&capabilities);
   TGarbageCollectionFinishCallback::registerCallback(
                                            &OnGarbageCollectionFinishForUnload);
 
@@ -472,7 +473,6 @@
     /* FullGC on G1, we handle it at callbackForG1Full() */
     if (!vmVal->getUseG1()) {
       TGarbageCollectionStartCallback::mergeCapabilities(&capabilities);
-      TGarbageCollectionFinishCallback::mergeCapabilities(&capabilities);
 
       if (vmVal->getUseCMS()) {
         TGarbageCollectionStartCallback::registerCallback(&OnCMSGCStart);
--- a/agent/src/heapstats-engines/snapShotContainer.cpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/snapShotContainer.cpp	Fri Jan 19 14:06:27 2018 +0900
@@ -19,25 +19,18 @@
  *
  */
 
+#include <utility>
+#include <algorithm>
+
 #include "globals.hpp"
 #include "snapShotContainer.hpp"
-
-/*!
- * \brief Pthread mutex for instance control.<br>
- * <br>
- * This mutex used in below process.<br>
- *   - TSnapShotContainer::getInstance @ snapShotContainer.cpp<br>
- *     To get older snapShotContainer instance from stockQueue.<br>
- *   - TSnapShotContainer::releaseInstance @ snapShotContainer.cpp<br>
- *     To add used snapShotContainer instance to stockQueue.<br>
- */
-pthread_mutex_t TSnapShotContainer::instanceLocker =
-    PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
+#include "classContainer.hpp"
 
 /*!
  * \brief Snapshot container instance stock queue.
  */
-TSnapShotQueue *TSnapShotContainer::stockQueue = NULL;
+tbb::concurrent_queue<TSnapShotContainer *>
+                                 *TSnapShotContainer::stockQueue = NULL;
 
 /*!
  * \brief Set of active TSnapShotContainer set
@@ -67,13 +60,12 @@
  */
 void TSnapShotContainer::globalFinalize(void) {
   if (likely(stockQueue != NULL)) {
-    /* Clear snapshot in queue. */
-    while (!stockQueue->empty()) {
-      TSnapShotContainer *item = stockQueue->front();
+    TSnapShotContainer *item;
 
+    /* Clear snapshots in queue. */
+    while (stockQueue->try_pop(item)) {
       /* Deallocate snapshot instance. */
       delete item;
-      stockQueue->pop();
     }
 
     /* Deallocate stock queue. */
@@ -90,26 +82,12 @@
  */
 TSnapShotContainer *TSnapShotContainer::getInstance(void) {
   TSnapShotContainer *result = NULL;
-
-  ENTER_PTHREAD_SECTION(&instanceLocker) {
-    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();
-        activeSnapShots.insert(result);
-      } catch (...) {
-        result = NULL;
-      }
-    }
+  if (!stockQueue->try_pop(result)) {
+    /* Create new snapshot container instance. */
+    result = new TSnapShotContainer();
+    TActiveSnapShots::accessor acc;
+    activeSnapShots.insert(acc, result);
   }
-  EXIT_PTHREAD_SECTION(&instanceLocker)
 
   return result;
 }
@@ -125,53 +103,27 @@
     return;
   }
 
-  bool existStockSpace = false;
-  ENTER_PTHREAD_SECTION(&instanceLocker) {
-    existStockSpace = (stockQueue->size() < MAX_STOCK_COUNT);
-  }
-  EXIT_PTHREAD_SECTION(&instanceLocker)
-
-  if (likely(existStockSpace)) {
-    /*
-     * We reset this flag.
-     * Because we need deallocating if failed to store to stock.
-     * E.g. Failed to get mutex at "pthread_mutex_lock/unlock"
-     *      or no more memory at "std::queue<T>::push()".
-     */
-    existStockSpace = false;
-
+  /*
+   * unsafe_size() might return actual size if it is accessed concurrently.
+   * However we use this function because we can use to decide cache count.
+   * SnapShot cache means best effort.
+   */
+  if (likely(stockQueue->unsafe_size() < MAX_STOCK_COUNT)) {
     /* Clear data. */
     instance->clear(false);
-
-    ENTER_PTHREAD_SECTION(&instanceLocker) {
-      try {
-        /* Store instance. */
-        stockQueue->push(instance);
-
-        existStockSpace = true;
-      } catch (...) {
-        /* Maybe faield to allocate memory. So we release instance. */
-      }
-    }
-    EXIT_PTHREAD_SECTION(&instanceLocker)
+    /* Store instance. */
+    stockQueue->push(instance);
+  } else {
+    /* Deallocate instance. */
+    activeSnapShots.erase(instance);
+    delete instance;
   }
-
-  ENTER_PTHREAD_SECTION(&instanceLocker)
-  {
-    if (unlikely(!existStockSpace)) {
-      /* Deallocate instance. */
-      activeSnapShots.erase(instance);
-      delete instance;
-    }
-  }
-  EXIT_PTHREAD_SECTION(&instanceLocker)
 }
 
 /*!
  * \brief TSnapshotContainer constructor.
  */
-TSnapShotContainer::TSnapShotContainer(bool isParent)
-    : counterMap(), containerMap() {
+TSnapShotContainer::TSnapShotContainer(void) : counterMap(), childrenMap() {
   /* Header setting. */
   this->_header.magicNumber = conf->CollectRefTree()->get()
                                 ? EXTENDED_REFTREE_SNAPSHOT
@@ -181,16 +133,6 @@
   this->_header.size = 0;
   memset((void *)&this->_header.gcCause[0], 0, 80);
 
-  /* Initialize each field. */
-  lockval = 0;
-  isParentContainer = isParent;
-
-  /* Create thread storage key. */
-  if (unlikely(isParent &&
-               pthread_key_create(&snapShotContainerKey, NULL) != 0)) {
-    throw "Failed to create pthread key";
-  }
-
   this->isCleared = true;
 }
 
@@ -199,45 +141,18 @@
  */
 TSnapShotContainer::~TSnapShotContainer(void) {
   /* Cleanup elements on counter map. */
-  for (TSizeMap::iterator it = counterMap.begin(); it != counterMap.end();
-       ++it) {
-    TClassCounter *clsCounter = (*it).second;
-    if (unlikely(clsCounter == NULL)) {
-      continue;
-    }
-
-    /* Deallocate field block cache. */
+  for (auto itr = counterMap.begin(); itr != counterMap.end(); itr++) {
+    TClassCounter *clsCounter = itr->second;
     free(clsCounter->offsets);
-
-    /* Deallocate children class list. */
-    TChildClassCounter *counter = clsCounter->child;
-    while (counter != NULL) {
-      TChildClassCounter *aCounter = counter;
-      counter = counter->next;
-
-      /* Deallocate TChildClassCounter. */
-      free(aCounter->counter);
-      free(aCounter);
-    }
-
-    /* Deallocate TClassCounter. */
     free(clsCounter->counter);
     free(clsCounter);
   }
 
-  /* Cleanup elements on snapshot container map. */
-  for (TLocalSnapShotContainer::iterator it = containerMap.begin();
-       it != containerMap.end(); ++it) {
-    delete (*it).second;
-  }
-
-  /* Clean maps. */
-  counterMap.clear();
-  containerMap.clear();
-
-  if (isParentContainer) {
-    /* Clean thread storage key. */
-    pthread_key_delete(snapShotContainerKey);
+  /* Cleanup elements on children map. */
+  for (auto itr = childrenMap.begin(); itr != childrenMap.end(); itr++) {
+    TChildClassCounter *childCounter = itr->second;
+    free(childCounter->counter);
+    free(childCounter);
   }
 }
 
@@ -271,19 +186,15 @@
 
   this->clearObjectCounter(cur->counter);
 
-  try {
-    /* Set counter map. */
-    counterMap[objData] = cur;
-  } catch (...) {
-    /*
-     * Maybe failed to allocate memory at "std::map::operator[]".
-     */
+  /* Set to counter map. */
+  TSizeMap::accessor acc;
+  if (!counterMap.insert(acc, std::make_pair(objData, cur))) {
     free(cur->counter);
     free(cur);
     cur = NULL;
   }
 
-  return cur;
+  return acc->second;
 }
 
 /*!
@@ -313,17 +224,27 @@
   this->clearObjectCounter(newCounter->counter);
   newCounter->objData = objData;
 
-  /* Chain children list. */
-  TChildClassCounter *counter = clsCounter->child;
-  if (unlikely(counter == NULL)) {
-    clsCounter->child = newCounter;
-  } else {
-    /* Get last counter. */
-    while (counter->next != NULL) {
-      counter = counter->next;
+  /* Set to children map. */
+  TChildrenMapKey key = std::make_pair(clsCounter, objData->klassOop);
+  TChildrenMap::accessor acc;
+  childrenMap.insert(acc, std::make_pair(key, newCounter));
+  acc.release();
+
+  /* Add new counter to children list */
+  spinLockWait(&clsCounter->spinlock);
+  {
+    TChildClassCounter *counter = clsCounter->child;
+    if (unlikely(counter == NULL)) {
+      clsCounter->child = newCounter;
+    } else {
+      /* Get last counter. */
+      while (counter->next != NULL) {
+        counter = counter->next;
+      }
+      counter->next = newCounter;
     }
-    counter->next = newCounter;
   }
+  spinLockRelease(&clsCounter->spinlock);
 
   return newCounter;
 }
@@ -378,36 +299,16 @@
     return;
   }
 
-  /* Get snapshot container's spin lock. */
-  spinLockWait(&lockval);
-  {
-    /* Clean heap usage information. */
-    for (TSizeMap::iterator it = counterMap.begin(); it != counterMap.end();
-         ++it) {
-      TClassCounter *clsCounter = (*it).second;
-      if (unlikely(clsCounter == NULL)) {
-        continue;
-      }
+  /* Cleanup elements on counter map. */
+  for (auto itr = counterMap.begin(); itr != counterMap.end(); itr++) {
+    TClassCounter *clsCounter = itr->second;
+    free(clsCounter->offsets);
+    clsCounter->offsets = NULL;
+    clsCounter->offsetCount = -1;
 
-      /* Deallocate field block cache. */
-      free(clsCounter->offsets);
-      clsCounter->offsets = NULL;
-      clsCounter->offsetCount = -1;
-
-      /* Reset counters. */
-      this->clearChildClassCounters(clsCounter);
-    }
-
-    /* Clean local snapshots. */
-    for (TLocalSnapShotContainer::iterator it = containerMap.begin();
-         it != containerMap.end(); ++it) {
-      (*it).second->clear(true);
-    }
-
-    this->isCleared = true;
+    /* Reset counters. */
+    clearChildClassCounters(clsCounter);
   }
-  /* Release snapshot container's spin lock. */
-  spinLockRelease(&lockval);
 }
 
 /*!
@@ -448,122 +349,34 @@
 }
 
 /*!
- * \brief Merge children data.
- */
-void TSnapShotContainer::mergeChildren(void) {
-  /* Get snapshot container's spin lock. */
-  spinLockWait(&lockval);
-  {
-    /* Loop each local snapshot container. */
-    for (TLocalSnapShotContainer::iterator it = this->containerMap.begin();
-         it != this->containerMap.end(); it++) {
-      /* Loop each class in snapshot container. */
-      TSizeMap *srcCounterMap = &(*it).second->counterMap;
-      for (TSizeMap::iterator it2 = srcCounterMap->begin();
-           it2 != srcCounterMap->end(); it2++) {
-        TClassCounter *srcClsCounter = (*it2).second;
-
-        /* Search or register class. */
-        TClassCounter *clsCounter = this->findClass((*it2).first);
-        if (unlikely(clsCounter == NULL)) {
-          clsCounter = this->pushNewClass((*it2).first);
-
-          /* If failed to search and register class. */
-          if (unlikely(clsCounter == NULL)) {
-            continue; /* Skip merge this class. */
-          }
-        }
-
-        /* Marge class heap usage. */
-        this->addInc(clsCounter->counter, srcClsCounter->counter);
-
-        /* Loop each children class. */
-        TChildClassCounter *counter = srcClsCounter->child;
-        while (counter != NULL) {
-          TObjectData *objData = counter->objData;
-
-          /* 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);
-          }
-
-          counter = counter->next;
-        }
-      }
-    }
-  }
-  /* 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);
-    }
-  }
+  /*
+   * This function is called at safepoint.
+   *   (from OnGarbageCollectionFinishForUnload() in classContainer.cpp)
+   * So we can use *unsafe* iterator access in tbb::concurrent_queue.
+   */
+  for (auto itr = unloadedList.unsafe_begin();
+       itr != unloadedList.unsafe_end(); itr++) {
+    TSizeMap::const_accessor acc;
+    if (counterMap.find(acc, *itr)) {
+      TClassCounter *clsCounter = acc->second;
+      counterMap.erase(acc);
+      acc.release();
 
-  /* 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;
+      TChildClassCounter *child = clsCounter->child;
+      while (child != NULL) {
+        TChildClassCounter *next = child->next;
+        childrenMap.erase(std::make_pair(clsCounter, child->objData->klassOop));
+        free(child->counter);
+        free(child);
+        child = next;
       }
-
-      childCounter = nextCounter;
     }
   }
-
-  /* Remove the target from local containers. */
-  for (TLocalSnapShotContainer::iterator container = containerMap.begin();
-       container != containerMap.end(); container++) {
-    container->second->removeObjectData(unloadedList);
-  }
 }
 
 /*!
@@ -572,13 +385,9 @@
  */
 void TSnapShotContainer::removeObjectDataFromAllSnapShots(
                                                  TClassInfoSet &unloadedList) {
-  ENTER_PTHREAD_SECTION(&instanceLocker)
-  {
-    for (TActiveSnapShots::iterator itr = activeSnapShots.begin();
-         itr != activeSnapShots.end(); itr++) {
-      (*itr)->removeObjectData(unloadedList);
-    }
+  for (auto itr = activeSnapShots.begin();
+       itr != activeSnapShots.end(); itr++) {
+    itr->first->removeObjectData(unloadedList);
   }
-  EXIT_PTHREAD_SECTION(&instanceLocker)
 }
 
--- a/agent/src/heapstats-engines/snapShotContainer.hpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/snapShotContainer.hpp	Fri Jan 19 14:06:27 2018 +0900
@@ -22,14 +22,14 @@
 #ifndef _SNAPSHOT_CONTAINER_HPP
 #define _SNAPSHOT_CONTAINER_HPP
 
-#include <pthread.h>
+#include <tbb/concurrent_hash_map.h>
+#include <tbb/concurrent_queue.h>
 
-#include <tr1/unordered_map>
-#include <tr1/unordered_set>
-#include <queue>
+#include <algorithm>
 
 #include "jvmInfo.hpp"
 #include "oopUtil.hpp"
+#include "classContainer.hpp"
 
 #if PROCESSOR_ARCH == X86
 #include "arch/x86/lock.inline.hpp"
@@ -66,34 +66,12 @@
 } TObjectCounter;
 
 /*!
- * \brief This structure stored class information.
- */
-typedef struct {
-  jlong tag;          /*!< Class tag.                                 */
-  jlong classNameLen; /*!< Class name.                                */
-  char *className;    /*!< Class name length.                         */
-  void *klassOop;     /*!< Java inner class object.                   */
-  jlong oldTotalSize; /*!< Class old total use size.                  */
-  TOopType oopType;   /*!< Type of class.                             */
-  jlong clsLoaderId;  /*!< Class loader instance id.                  */
-  jlong clsLoaderTag; /*!< Class loader class tag.                    */
-  jlong instanceSize; /*!< Class size if this class is instanceKlass. */
-} 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 {
   TObjectCounter *counter;  /*!< Java inner class object. */
   TObjectData *objData;     /*!< Class information.       */
   TChildClassCounter *next; /*!< Pointer of next object.  */
-  unsigned int callCount;   /*!< Call count.              */
 };
 
 /*!
@@ -136,31 +114,25 @@
 class TSnapShotContainer;
 
 /*!
- * \brief This type is for queue store snapshot information.
+ * \brief Type is for map of storing object counters.
  */
-typedef std::queue<TSnapShotContainer *> TSnapShotQueue;
-
-/*!
- * \brief This type is for map stored size information.
- */
-typedef std::tr1::unordered_map<TObjectData *, TClassCounter *,
-                                TNumericalHasher<void *> > TSizeMap;
+typedef tbb::concurrent_hash_map<TObjectData *, TClassCounter *,
+                                 TPointerHasher<TObjectData *> > TSizeMap;
 
 /*!
- * \brief This class is stored class object usage on heap.
+ * \brief Container of active snapshot list.
  */
-class TSnapShotContainer;
+typedef tbb::concurrent_hash_map<TSnapShotContainer *, int> TActiveSnapShots;
+
+typedef std::pair<TClassCounter *, PKlassOop> TChildrenMapKey;
+
+typedef tbb::concurrent_hash_map
+                           <TChildrenMapKey, TChildClassCounter *> TChildrenMap;
 
 /*!
- * \brief This type is for TSnapShotContainer in Thread-Local-Storage.
+ * \brief Snapshot container instance stock queue.
  */
-typedef std::tr1::unordered_map<pthread_t, TSnapShotContainer *,
-                                TNumericalHasher<pthread_t> >
-    TLocalSnapShotContainer;
-
-typedef std::tr1::unordered_set<TSnapShotContainer *,
-                                TNumericalHasher<void *> > TActiveSnapShots;
-
+typedef tbb::concurrent_queue<TSnapShotContainer *> TSnapShotQueue;
 
 /*!
  * \brief This class is stored class object usage on heap.
@@ -265,8 +237,8 @@
    *         Value is null, if class is not found.
    */
   inline TClassCounter *findClass(TObjectData *objData) {
-    TSizeMap::iterator it = counterMap.find(objData);
-    return (it != counterMap.end()) ? (*it).second : NULL;
+    TSizeMap::const_accessor acc;
+    return counterMap.find(acc, objData) ? acc->second : NULL;
   }
 
   /*!
@@ -277,44 +249,10 @@
    *         Value is null, if class is not found.
    */
   inline TChildClassCounter *findChildClass(TClassCounter *clsCounter,
-                                            void *klassOop) {
-    TChildClassCounter *prevCounter = NULL;
-    TChildClassCounter *morePrevCounter = NULL;
-    TChildClassCounter *counter = clsCounter->child;
-
-    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++;
-
-      /* If counter need move to list head. */
-      if (prevCounter != NULL && prevCounter->callCount <= counter->callCount) {
-        prevCounter->next = counter->next;
-        if (morePrevCounter != NULL) {
-          /* Move to near list head. */
-          morePrevCounter->next = counter;
-        } else {
-          /* Move list head. */
-          clsCounter->child = counter;
-        }
-        counter->next = prevCounter;
-      }
-    }
-    return counter;
+                                            PKlassOop klassOop) {
+    TChildrenMapKey key = std::make_pair(clsCounter, klassOop);
+    TChildrenMap::const_accessor acc;
+    return childrenMap.find(acc, key) ? acc->second : NULL;
   }
 
   /*!
@@ -344,65 +282,6 @@
   void clear(bool isForce);
 
   /*!
-   * \brief Get local snapshot container with each threads.
-   * \return Local snapshot container instance for this thread.
-   */
-  inline TSnapShotContainer *getLocalContainer(void) {
-    TSnapShotContainer *result = NULL;
-
-    /* Get root and local snapshot conatiner. */
-    result = (TSnapShotContainer *)pthread_getspecific(snapShotContainerKey);
-
-    /* If not exists local container. */
-    if (unlikely(result == NULL)) {
-      pthread_t selfThreadId = pthread_self();
-
-      /* Get snapshot container's spin lock. */
-      spinLockWait(&lockval);
-      {
-        TLocalSnapShotContainer::iterator it = containerMap.find(selfThreadId);
-        if (it != containerMap.end()) {
-          result = (*it).second;
-        }
-      }
-      /* Release snapshot container's spin lock. */
-      spinLockRelease(&lockval);
-
-      if (unlikely(result == NULL)) {
-        try {
-          result = new TSnapShotContainer(false);
-        } catch (...) {
-          /* Maybe raise badalloc exception. */
-          return NULL;
-        }
-
-        /* Get snapshot container's spin lock. */
-        spinLockWait(&lockval);
-        {
-          try {
-            containerMap[selfThreadId] = result;
-          } catch (...) {
-            /* Failed to add map. Maybe no more free memory. */
-            delete result;
-            result = NULL;
-          }
-        }
-        /* Release snapshot container's spin lock. */
-        spinLockRelease(&lockval);
-      }
-
-      /* Set local snapshot conatiner. */
-      pthread_setspecific(snapShotContainerKey, result);
-    }
-    return result;
-  }
-
-  /*!
-   * \brief Merge children data.
-   */
-  virtual void mergeChildren(void);
-
-  /*!
    * \brief Set "isCleared" flag.
    */
   inline void setIsCleared(bool flag) { this->isCleared = flag; }
@@ -424,7 +303,7 @@
   /*!
    * \brief TSnapshotContainer constructor.
    */
-  TSnapShotContainer(bool isParent = true);
+  TSnapShotContainer(void);
   /*!
    * \brief TSnapshotContainer destructor.
    */
@@ -449,17 +328,6 @@
   void clearChildClassCounters(TClassCounter *counter);
 
   /*!
-   * \brief Pthread mutex for instance control.<br>
-   * <br>
-   * This mutex used in below process.<br>
-   *   - TSnapShotContainer::getInstance @ snapShotContainer.cpp<br>
-   *     To get older snapShotContainer instance from stockQueue.<br>
-   *   - TSnapShotContainer::releaseInstance @ snapShotContainer.cpp<br>
-   *     To add used snapShotContainer instance to stockQueue.<br>
-   */
-  static pthread_mutex_t instanceLocker;
-
-  /*!
    * \brief Snapshot container instance stock queue.
    */
   static TSnapShotQueue *stockQueue;
@@ -470,16 +338,16 @@
   const static unsigned int MAX_STOCK_COUNT = 2;
 
   /*!
-   * \brief Maps of counter of each java class.
+   * \brief Map for TClassCounter.
    */
   TSizeMap counterMap;
 
   /*!
-   * \brief Maps of TSnapShotContainer and thread.
+   * \brief Map for TChildClassCounter.
    */
-  TLocalSnapShotContainer containerMap;
+  TChildrenMap childrenMap;
 
-  RELEASE_ONLY(private :)
+ private:
 
   /*!
    * \brief Snapshot header.
@@ -487,21 +355,6 @@
   volatile TSnapShotFileHeader _header;
 
   /*!
-   * \brief SpinLock variable for each snapshot class container.
-   */
-  volatile int lockval;
-
-  /*!
-   * \brief The thread key for map of local snapshot containers.
-   */
-  pthread_key_t snapShotContainerKey;
-
-  /*!
-   * \brief Is this container is parent container ?
-   */
-  bool isParentContainer;
-
-  /*!
    * \brief Is this container is cleared ?
    */
   volatile bool isCleared;
@@ -562,7 +415,6 @@
     child_counter->counter->count = 0;
     child_counter->counter->total_size = 0;
 
-    // child_counter->callCount >>= 1;
     child_counter = child_counter->next;
   }
 
--- a/agent/src/heapstats-engines/snapShotMain.cpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/snapShotMain.cpp	Fri Jan 19 14:06:27 2018 +0900
@@ -42,7 +42,6 @@
 typedef struct {
   TSnapShotContainer *snapshot;  /*!< Container of taking snapshot. */
   TClassCounter *counter;        /*!< Counter of class heap usage.  */
-  TClassContainer *clsContainer; /*!< Container of class data.      */
 } TCollectContainers;
 
 /* Variable defines. */
@@ -74,19 +73,6 @@
 pthread_mutex_t dumpMutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
 
 /*!
- * \brief Pthread mutex for change snapshot queue.<br>
- * <br>
- * This mutex used in below process.<br>
- *   - TakeSnapShot @ snapShotMain.cpp<br>
- *     To add snapshot by JVMTI to output wait queue.<br>
- *   - popSnapShotQueue @ snapShotMain.cpp<br>
- *     To get snapshot from output wait queue.<br>
- *   - addSnapShotQueue @ snapShotMain.cpp<br>
- *     To add snapshot by GC to output wait queue.<br>
- */
-pthread_mutex_t queueMutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
-
-/*!
  * \brief Pthread mutex for JVMTI IterateOverHeap calling.<br>
  * <br>
  * This mutex used in below process.<br>
@@ -194,24 +180,8 @@
  *         So that, you should be additionally handling snapshot instance.
  */
 inline bool addSnapShotQueue(TSnapShotContainer *snapshot) {
-  bool isSucceed = false;
-  /* Push output waiting queue. */
-  ENTER_PTHREAD_SECTION(&queueMutex) {
-    try {
-      snapStockQueue.push(snapshot);
-
-      /* Reset exception flag. */
-      isSucceed = true;
-    } catch (...) {
-      /*
-       * Maybe faield to allocate memory at "std:queue<T>::push()".
-       * So we throw exception again at after release lock.
-       */
-    }
-  }
-  EXIT_PTHREAD_SECTION(&queueMutex)
-
-  return isSucceed;
+  snapStockQueue.push(snapshot);
+  return true;
 }
 
 /*!
@@ -221,17 +191,8 @@
  */
 inline TSnapShotContainer *popSnapShotQueue(void) {
   TSnapShotContainer *snapshot = NULL;
-
-  /* Get snapshot data from waiting queue. */
-  ENTER_PTHREAD_SECTION(&queueMutex) {
-    if (likely(!snapStockQueue.empty())) {
-      snapshot = snapStockQueue.front();
-      snapStockQueue.pop();
-    }
-  }
-  EXIT_PTHREAD_SECTION(&queueMutex)
-
-  return snapshot;
+  bool succeeded = snapStockQueue.try_pop(snapshot);
+  return succeeded ? snapshot : NULL;
 }
 
 /*!
@@ -329,26 +290,14 @@
 
 /*!
  * \brief Get class information.
- * \param aClsContainer [in] Search target class container.
  * \param klassOop      [in] Pointer of child java class object(KlassOopDesc).
  * \return Pointer of information of expceted class by klassOop.
  */
-inline TObjectData *getObjectDataFromKlassOop(TClassContainer *aClsContainer,
-                                              void *klassOop) {
-  TObjectData *clsData = NULL;
-
-  /* Search child class at local class container. */
-  clsData = aClsContainer->findClass(klassOop);
+inline TObjectData *getObjectDataFromKlassOop(void *klassOop) {
+  TObjectData *clsData = clsContainer->findClass(klassOop);
   if (unlikely(clsData == NULL)) {
-    /* Search child class at root class container. */
-    clsData = clsContainer->findClass(klassOop);
-    if (unlikely(clsData == NULL)) {
-      /* Push new loaded class to root class container. */
-      clsData = clsContainer->pushNewClass(klassOop);
-    } else {
-      /* Push a loaded class to local class container. */
-      aClsContainer->pushNewClass(klassOop, clsData);
-    }
+    /* Push new loaded class to root class container. */
+    clsData = clsContainer->pushNewClass(klassOop);
   }
 
   return clsData;
@@ -367,21 +316,19 @@
     return;
   }
 
-  TSnapShotContainer *localSnapshot = containerInfo->snapshot;
+  TSnapShotContainer *snapshot = containerInfo->snapshot;
   TClassCounter *parentCounter = containerInfo->counter;
-  TClassContainer *localClsContainer = containerInfo->clsContainer;
 
   TChildClassCounter *clsCounter = NULL;
 
   /* Search child class. */
-  clsCounter = localSnapshot->findChildClass(parentCounter, klassOop);
+  clsCounter = snapshot->findChildClass(parentCounter, klassOop);
 
   if (unlikely(clsCounter == NULL)) {
     /* Get child class information. */
-    TObjectData *clsData =
-        getObjectDataFromKlassOop(localClsContainer, klassOop);
+    TObjectData *clsData = getObjectDataFromKlassOop(klassOop);
     /* Push new child loaded class. */
-    clsCounter = localSnapshot->pushNewChildClass(parentCounter, clsData);
+    clsCounter = snapshot->pushNewChildClass(parentCounter, clsData);
   }
 
   if (unlikely(clsCounter == NULL)) {
@@ -404,7 +351,7 @@
   }
 
   /* Count perent class size and instance count. */
-  localSnapshot->FastInc(clsCounter->counter, size);
+  snapshot->FastInc(clsCounter->counter, size);
 }
 
 /*!
@@ -414,16 +361,8 @@
  */
 inline void calculateObjectUsage(TSnapShotContainer *snapshot, void *oop) {
   void *klassOop = getKlassOopFromOop(oop);
-  TClassContainer *workClsContainer = clsContainer->getLocalContainer();
   /* Sanity check. */
-  if (unlikely(snapshot == NULL || klassOop == NULL ||
-               workClsContainer == NULL)) {
-    return;
-  }
-
-  TSnapShotContainer *localSnapshot = snapshot->getLocalContainer();
-  if (unlikely(localSnapshot == NULL)) {
-    logger->printCritMsg("Couldn't get local snapshot container!");
+  if (unlikely(snapshot == NULL || klassOop == NULL)) {
     return;
   }
 
@@ -433,17 +372,17 @@
   TObjectData *clsData = NULL;
 
   /* Get class information. */
-  clsData = getObjectDataFromKlassOop(workClsContainer, klassOop);
+  clsData = getObjectDataFromKlassOop(klassOop);
   if (unlikely(clsData == NULL)) {
     logger->printCritMsg("Couldn't get ObjectData!");
     return;
   }
 
   /* Search class. */
-  clsCounter = localSnapshot->findClass(clsData);
+  clsCounter = snapshot->findClass(clsData);
   if (unlikely(clsCounter == NULL)) {
     /* Push new loaded class. */
-    clsCounter = localSnapshot->pushNewClass(clsData);
+    clsCounter = snapshot->pushNewClass(clsData);
   }
 
   if (unlikely(clsCounter == NULL)) {
@@ -468,7 +407,7 @@
   }
 
   /* Count perent class size and instance count. */
-  localSnapshot->FastInc(clsCounter->counter, size);
+  snapshot->FastInc(clsCounter->counter, size);
 
   /* If we should not collect reftree or oop has no field. */
   if (!conf->CollectRefTree()->get() || !hasOopField(oopType)) {
@@ -476,9 +415,8 @@
   }
 
   TCollectContainers containerInfo;
-  containerInfo.snapshot = localSnapshot;
+  containerInfo.snapshot = snapshot;
   containerInfo.counter = clsCounter;
-  containerInfo.clsContainer = workClsContainer;
 
   TOopMapBlock *offsets = NULL;
   int offsetCount = 0;
--- a/agent/src/heapstats-engines/snapShotProcessor.cpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/snapShotProcessor.cpp	Fri Jan 19 14:06:27 2018 +0900
@@ -87,10 +87,7 @@
       if (likely(controller->_numRequests > 0)) {
         controller->_numRequests--;
         needProcess = true;
-        if (likely(!controller->snapQueue.empty())) {
-          snapshot = controller->snapQueue.front();
-          controller->snapQueue.pop();
-        }
+        controller->snapQueue.try_pop(snapshot);
       }
 
       /* Check remaining work. */
@@ -106,9 +103,6 @@
         static const char *label = "Write SnapShot and calculation";
         TElapsedTimer elapsedTime(label);
 
-        /* Marge children snapshot's data to parent snapshot. */
-        snapshot->mergeChildren();
-
         /* Output class-data. */
         result = controller->_container->afterTakeSnapShot(snapshot, &ranking);
       }
--- a/agent/src/heapstats-engines/threadRecorder.cpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/threadRecorder.cpp	Fri Jan 19 14:06:27 2018 +0900
@@ -353,7 +353,6 @@
 TThreadRecorder::TThreadRecorder(size_t buffer_size) : threadIDMap() {
   aligned_buffer_size = ALIGN_SIZE_UP(buffer_size, systemPageSize);
   bufferLockVal = 0;
-  idmapLockVal = 0;
 
   /* manpage of mmap(2):
    *
@@ -380,17 +379,9 @@
   munmap(record_buffer, aligned_buffer_size);
 
   /* Deallocate memory for thread name. */
-  spinLockWait(&idmapLockVal);
-  {
-    for (std::tr1::unordered_map<jlong, char *,
-                                 TNumericalHasher<jlong> >::iterator itr =
-                                                            threadIDMap.begin();
-         itr != threadIDMap.end(); itr++) {
-      free(itr->second);
-    }
+  for (auto itr = threadIDMap.begin(); itr != threadIDMap.end(); itr++) {
+    free(itr->second);
   }
-  spinLockRelease(&idmapLockVal);
-
 }
 
 /*!
@@ -655,27 +646,21 @@
   char bom = BOM;
   write(fd, &bom, sizeof(char));
 
-  spinLockWait(&idmapLockVal);
-  {
-    /* Dump thread list. */
-    int threadIDMapSize = threadIDMap.size();
-    write(fd, &threadIDMapSize, sizeof(int));
+  /* Dump thread list. */
+  auto workIDMap(threadIDMap);
+  int threadIDMapSize = workIDMap.size();
+  write(fd, &threadIDMapSize, sizeof(int));
 
-    for (std::tr1::unordered_map<jlong, char *,
-                                 TNumericalHasher<jlong> >::iterator itr =
-             threadIDMap.begin();
-         itr != threadIDMap.end(); itr++) {
-      jlong id = itr->first;
-      int classname_length = strlen(itr->second);
-      write(fd, &id, sizeof(jlong));
-      write(fd, &classname_length, sizeof(int));
-      write(fd, itr->second, classname_length);
-    }
+  for (auto itr = workIDMap.begin(); itr != workIDMap.end(); itr++) {
+    jlong id = itr->first;
+    int classname_length = strlen(itr->second);
+    write(fd, &id, sizeof(jlong));
+    write(fd, &classname_length, sizeof(int));
+    write(fd, itr->second, classname_length);
+  }
 
-    /* Dump thread event. */
-    write(fd, record_buffer, aligned_buffer_size);
-  }
-  spinLockRelease(&idmapLockVal);
+  /* Dump thread event. */
+  write(fd, record_buffer, aligned_buffer_size);
 
   close(fd);
 }
@@ -760,17 +745,13 @@
   jvmtiThreadInfo threadInfo;
   jvmti->GetThreadInfo(thread, &threadInfo);
 
-  spinLockWait(&idmapLockVal);
   {
-    char *current_val = threadIDMap[id];
-
-    if (unlikely(current_val != NULL)) {
-      free(current_val);
+    TThreadIDMap::accessor acc;
+    if (!threadIDMap.insert(acc, id)) {
+      free(acc->second);
     }
-
-    threadIDMap[id] = strdup(threadInfo.name);
+    acc->second = strdup(threadInfo.name);
   }
-  spinLockRelease(&idmapLockVal);
 
   jvmti->Deallocate((unsigned char *)threadInfo.name);
 }
@@ -814,17 +795,11 @@
   eventRecord.additionalData = additionalData;
 
   if (unlikely(top_of_buffer->event == ThreadEnd)) {
-    spinLockWait(&idmapLockVal);
-    {
-      std::tr1::unordered_map<jlong, char *, TNumericalHasher<jlong> >
-              ::iterator entry = threadIDMap.find(top_of_buffer->thread_id);
-
-      if (likely(entry != threadIDMap.end())) {
-        free(entry->second);
-        threadIDMap.erase(entry);
-      }
+    TThreadIDMap::accessor acc;
+    if (threadIDMap.find(acc, top_of_buffer->thread_id)) {
+      free(acc->second);
+      threadIDMap.erase(acc);
     }
-    spinLockRelease(&idmapLockVal);
   }
 
   spinLockWait(&bufferLockVal);
--- a/agent/src/heapstats-engines/threadRecorder.hpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/threadRecorder.hpp	Fri Jan 19 14:06:27 2018 +0900
@@ -27,7 +27,7 @@
 
 #include <stddef.h>
 
-#include <tr1/unordered_map>
+#include <tbb/concurrent_hash_map.h>
 
 /*!
  * \brief Header of recording data.
@@ -79,6 +79,12 @@
 } TThreadEvent;
 
 /*!
+ * \brief Type of ThreadID-ThreadName map.
+ */
+typedef tbb::concurrent_hash_map<jlong, char *, TNumericalHasher<jlong> >
+                                                                  TThreadIDMap;
+
+/*!
  * \brief Implementation of HeapStats Thread Recorder.
  *        This instance must be singleton.
  */
@@ -111,7 +117,7 @@
    * \brief ThreadID-ThreadName map.
    *        Key is thread ID, Value is thread name.
    */
-  std::tr1::unordered_map<jlong, char *, TNumericalHasher<jlong> > threadIDMap;
+  TThreadIDMap threadIDMap;
 
   /*!
    * \brief SpinLock variable for Ring Buffer operation.
@@ -119,11 +125,6 @@
   volatile int bufferLockVal;
 
   /*!
-   * \brief SpinLock variable for Thread ID map operation.
-   */
-  volatile int idmapLockVal;
-
-  /*!
    * \brief Instance of TThreadRecorder.
    */
   static TThreadRecorder *inst;
--- a/agent/src/heapstats-engines/util.hpp	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/heapstats-engines/util.hpp	Fri Jan 19 14:06:27 2018 +0900
@@ -361,20 +361,33 @@
 /* Classes. */
 
 /*!
- * \brief Hasher class for std::tr1::unordered_map.
- *        This template class will be used when key is numeric type.
- *        (int, pointer, etc)
+ * \brief Hasher class for tbb::concurrent_hash_map.
+ *        This template class is for number type except pointers.
  */
 template <typename T>
 class TNumericalHasher {
- public:
-  /*!
-   * \brief Get hash value from designated value.
-   *        This function always return convert to integer only.
-   * \param val [in] Hash source data.
-   * \return Hash value.
-   */
-  size_t operator()(const T &val) const { return (size_t)val; };
+  public:
+
+   static size_t hash(const T v) {
+     return v;
+   }
+
+   static bool equal(const T v1, const T v2) {
+     return v1 == v2;
+   }
+
+};
+
+/*!
+ * \brief Hasher class for tbb::concurrent_hash_map.
+ *        This template class is for pointer type.
+ */
+template <typename T>
+class TPointerHasher : public TNumericalHasher<T> {
+  public:
+    static size_t hash(const T v) {
+      return reinterpret_cast<size_t>(v) / sizeof(T);
+    }
 };
 
 /*!
--- a/agent/src/iotracer/Makefile.in	Tue Dec 05 16:18:49 2017 +0900
+++ b/agent/src/iotracer/Makefile.in	Fri Jan 19 14:06:27 2018 +0900
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
--- a/configure	Tue Dec 05 16:18:49 2017 +0900
+++ b/configure	Fri Jan 19 14:06:27 2018 +0900
@@ -5600,6 +5600,47 @@
   as_fn_error $? "BFD library was not found." "$LINENO" 5
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lpthread" >&5
+$as_echo_n "checking for main in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_main+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_main=yes
+else
+  ac_cv_lib_pthread_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_main" >&5
+$as_echo "$ac_cv_lib_pthread_main" >&6; }
+if test "x$ac_cv_lib_pthread_main" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "Posix thread library was not found." "$LINENO" 5
+fi
+
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -6501,6 +6542,19 @@
 fi
 
 
+for ac_header in sys/auxv.h
+do :
+  ac_fn_cxx_check_header_mongrel "$LINENO" "sys/auxv.h" "ac_cv_header_sys_auxv_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_auxv_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_AUXV_H 1
+_ACEOF
+
+fi
+
+done
+  # Supplemental headers
+
 # Check Container insert/erase and iterator constness (N2350)
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for N2350" >&5
 $as_echo_n "checking for N2350... " >&6; }
@@ -8110,7 +8164,70 @@
 if test -n "$ARCH"; then
   CXXFLAGS+=" -march=$ARCH";
   CCASFLAGS+=" -march=$ARCH"
-fi
+elif test x"$PROCESSOR_TYPE" = "xarm"; then  # Raspberry Pi 2 support
+  CXXFLAGS+=" -march=armv7-a"
+  CCASFLAGS+=" -march=armv7-a"
+fi
+
+# check TBB --------------------------------------------------------------------
+for ac_header in  \
+  tbb/concurrent_hash_map.h tbb/concurrent_queue.h \
+
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  as_fn_error $? "Not found common header files." "$LINENO" 5
+fi
+
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ltbb" >&5
+$as_echo_n "checking for main in -ltbb... " >&6; }
+if ${ac_cv_lib_tbb_main+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ltbb  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  ac_cv_lib_tbb_main=yes
+else
+  ac_cv_lib_tbb_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tbb_main" >&5
+$as_echo "$ac_cv_lib_tbb_main" >&6; }
+if test "x$ac_cv_lib_tbb_main" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTBB 1
+_ACEOF
+
+  LIBS="-ltbb $LIBS"
+
+else
+  as_fn_error $? "TBB library was not found." "$LINENO" 5
+fi
+
 
 # end processor type -----------------------------------------------------------
 
--- a/configure.ac	Tue Dec 05 16:18:49 2017 +0900
+++ b/configure.ac	Fri Jan 19 14:06:27 2018 +0900
@@ -54,6 +54,8 @@
 AC_CHECK_LIB([iberty], [main], [], [])
 AC_CHECK_LIB([bfd], [main], [],
   [AC_MSG_ERROR([BFD library was not found.])])
+AC_CHECK_LIB([pthread], [main], [],
+  [AC_MSG_ERROR([Posix thread library was not found.])])
 AC_CACHE_SAVE
 
 # Checks for common header files.
@@ -110,6 +112,8 @@
 )
 AM_CONDITIONAL(USE_PCRE, test -n "${ac_cv_header_pcre_h}")
 
+AC_CHECK_HEADERS([sys/auxv.h], [], [])  # Supplemental headers
+
 # Check Container insert/erase and iterator constness (N2350)
 AC_MSG_CHECKING([for N2350])
 
@@ -218,8 +222,17 @@
 if test -n "$ARCH"; then
   CXXFLAGS+=" -march=$ARCH";
   CCASFLAGS+=" -march=$ARCH"
+elif test x"$PROCESSOR_TYPE" = "xarm"; then  # Raspberry Pi 2 support
+  CXXFLAGS+=" -march=armv7-a"
+  CCASFLAGS+=" -march=armv7-a"
 fi
 
+# check TBB --------------------------------------------------------------------
+AC_CHECK_HEADERS([ \
+  tbb/concurrent_hash_map.h tbb/concurrent_queue.h \
+  ], [], [AC_MSG_ERROR([Not found common header files.])])
+AC_CHECK_LIB([tbb], [main], [], [AC_MSG_ERROR([TBB library was not found.])])
+
 # end processor type -----------------------------------------------------------
 
 # get JDK path -----------------------------------------------------------------
--- a/mbean/Makefile.in	Tue Dec 05 16:18:49 2017 +0900
+++ b/mbean/Makefile.in	Fri Jan 19 14:06:27 2018 +0900
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
--- a/mbean/native/Makefile.in	Tue Dec 05 16:18:49 2017 +0900
+++ b/mbean/native/Makefile.in	Fri Jan 19 14:06:27 2018 +0900
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
--- a/specs/heapstats.spec	Tue Dec 05 16:18:49 2017 +0900
+++ b/specs/heapstats.spec	Fri Jan 19 14:06:27 2018 +0900
@@ -19,6 +19,7 @@
 
 # Requires for running
 Requires: pcre >= 6
+Requires: tbb
 
 # Requires for building
 BuildRequires: pcre-devel >= 6
@@ -28,6 +29,7 @@
 BuildRequires: binutils-devel
 BuildRequires: autoconf
 BuildRequires: automake
+BuildRequires: tbb-devel
 
 %if 0%{?WITH_ANALYZER:1}
 BuildRequires: java-1.8.0-openjdk-openjfx-devel
@@ -166,6 +168,8 @@
 %endif
 
 %changelog
+* Thu Jan 18 2018 Yasumasa Suenaga <yasuenag@gmail.com>
+- Add dependencies to TBB
 * Tue Jul 11 2017 Yasumasa Suenaga <yasuenag@gmail.com>
 - Add Analyzer package.
 * Tue Feb 09 2016 KUBOTA Yuji <kubota.yuji@lab.ntt.co.jp>