├── Test.java ├── shell.h ├── agentthread.h ├── agentthread.cc ├── io.h ├── io.cc ├── memory.h ├── threads.h ├── base.h ├── base.cc ├── makefile ├── shell.cc ├── outOfMemory.cc ├── threads.cc ├── memory.cc └── README.md /Test.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.List; 3 | 4 | /** 5 | * Test class that guarantees an OOM exception. 6 | */ 7 | public class Test { 8 | static class OOMList extends ArrayList { 9 | } 10 | 11 | public static void main(String[] args) { 12 | List strings = new OOMList(); 13 | List ints = new OOMList(); 14 | 15 | int i = 0; 16 | while (true) { 17 | strings.add("A really really long string." + i); 18 | ints.add(i); 19 | ints.add(i + 1); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /shell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * shell.h 3 | * 4 | * Original source is Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef POLARBEAR_SHELL_H 20 | #define POLARBEAR_SHELL_H 21 | 22 | 23 | #include "jvmti.h" 24 | #include "jni.h" 25 | 26 | 27 | void JNICALL shellServer(jvmtiEnv* jvmti, JNIEnv* jni, void *pData); 28 | 29 | void closeShellServer(); 30 | 31 | 32 | #endif -------------------------------------------------------------------------------- /agentthread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * agentthread.h 3 | * 4 | * Original source is Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef POLARBEAR_AGENT_THREAD_H 20 | #define POLARBEAR_AGENT_THREAD_H 21 | 22 | 23 | #include "jvmti.h" 24 | #include "jni.h" 25 | 26 | void createAgentThread(jvmtiEnv* jvmti, JNIEnv* env, jvmtiStartFunction proc, void *pArg); 27 | 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /agentthread.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * agentthread.cc 3 | * 4 | * Original source is Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "agentthread.h" 26 | #include "base.h" 27 | 28 | 29 | static jthread allocateThread(JNIEnv *env) { 30 | jclass thrClass = env->FindClass("java/lang/Thread"); 31 | jmethodID cid = env->GetMethodID(thrClass, "", "()V"); 32 | return env->NewObject(thrClass, cid); 33 | } 34 | 35 | void createAgentThread(jvmtiEnv* jvmti, JNIEnv* env, jvmtiStartFunction proc, void *pArg) { 36 | CHECK(jvmti->RunAgentThread(allocateThread(env), proc, pArg, JVMTI_THREAD_NORM_PRIORITY)); 37 | } 38 | -------------------------------------------------------------------------------- /io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * io.h 3 | * 4 | * Original source is Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef POLARBEAR_IO_H 20 | #define POLARBEAR_IO_H 21 | 22 | #include 23 | 24 | 25 | class Output { 26 | public: 27 | virtual int printf(const char *msg, ...) = 0; 28 | virtual void flush() = 0; 29 | }; 30 | 31 | 32 | class FileOutput : public Output { 33 | private: 34 | FILE *f; 35 | 36 | public: 37 | FileOutput(FILE *_f) : f(_f) {} 38 | 39 | virtual int printf(const char *msg, ...); 40 | virtual void flush(); 41 | }; 42 | 43 | 44 | class SocketOutput : public Output { 45 | private: 46 | int socket; 47 | 48 | public: 49 | SocketOutput(int _socket) : socket(_socket) {} 50 | 51 | virtual int printf(const char *msg, ...); 52 | virtual void flush(); 53 | }; 54 | 55 | 56 | #endif -------------------------------------------------------------------------------- /io.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * io.cc 3 | * 4 | * Original source is Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "io.h" 26 | 27 | 28 | int FileOutput::printf(const char *msg, ...) { 29 | va_list argList; 30 | va_start(argList, msg); 31 | 32 | int result = vfprintf(this->f, msg, argList); 33 | 34 | va_end(argList); 35 | 36 | return result; 37 | } 38 | 39 | 40 | void FileOutput::flush() { 41 | fflush(this->f); 42 | } 43 | 44 | 45 | int writestring(int sockd, const char *vptr, int n) { 46 | int nwritten; 47 | const char *buffer = vptr; 48 | int nleft = n; 49 | 50 | while (nleft > 0) { 51 | if ((nwritten = write(sockd, buffer, nleft)) <= 0) { 52 | if (errno == EINTR) { 53 | nwritten = 0; 54 | } else { 55 | return -1; 56 | } 57 | } 58 | nleft -= nwritten; 59 | buffer += nwritten; 60 | } 61 | 62 | return n; 63 | } 64 | 65 | 66 | int SocketOutput::printf(const char *msg, ...) { 67 | char buffer[1000]; 68 | 69 | va_list argList; 70 | va_start(argList, msg); 71 | 72 | int len = vsprintf(buffer, msg, argList); 73 | 74 | va_end(argList); 75 | 76 | return writestring(this->socket, buffer, len); 77 | } 78 | 79 | 80 | void SocketOutput::flush() { 81 | // Do nothing for now. 82 | } 83 | -------------------------------------------------------------------------------- /memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * memory.h 3 | * 4 | * Originally based on http://hope.nyc.ny.us/~lprimak/java/demo/jvmti/heapViewer/ 5 | * 6 | * Original source is Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved. 7 | * 8 | * Modifications are Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 13 | * -Redistribution of source code must retain the above copyright notice, this 14 | * list of conditions and the following disclaimer. 15 | * 16 | * -Redistribution in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * 20 | * Neither the name of Sun Microsystems, Inc. or the names of contributors may 21 | * be used to endorse or promote products derived from this software without 22 | * specific prior written permission. 23 | * 24 | * This software is provided "AS IS," without a warranty of any kind. ALL 25 | * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING 26 | * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 27 | * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") 28 | * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 29 | * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 30 | * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 31 | * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 32 | * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 33 | * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 34 | * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 35 | * 36 | * You acknowledge that this software is not designed, licensed or intended 37 | * for use in the design, construction, operation or maintenance of any 38 | * nuclear facility. 39 | */ 40 | 41 | 42 | #ifndef POLARBEAR_MEMORY_H 43 | #define POLARBEAR_MEMORY_H 44 | 45 | 46 | #include "jni.h" 47 | #include "jvmti.h" 48 | 49 | #include "io.h" 50 | 51 | void printHistogram(jvmtiEnv *jvmti, Output *out, bool includeReferrers); 52 | 53 | void printClassStats(jvmtiEnv *jvmti, const char *signature, Output *out, bool retainedSize); 54 | 55 | void printReferrers(jvmtiEnv *jvmti, const char *signature, Output *out); 56 | 57 | #endif -------------------------------------------------------------------------------- /threads.h: -------------------------------------------------------------------------------- 1 | /* 2 | * threads.h 3 | * 4 | * Originally based on http://hope.nyc.ny.us/~lprimak/java/demo/jvmti/heapViewer/ 5 | * 6 | * Original source is Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved. 7 | * 8 | * Modifications are Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 13 | * -Redistribution of source code must retain the above copyright notice, this 14 | * list of conditions and the following disclaimer. 15 | * 16 | * -Redistribution in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * 20 | * Neither the name of Sun Microsystems, Inc. or the names of contributors may 21 | * be used to endorse or promote products derived from this software without 22 | * specific prior written permission. 23 | * 24 | * This software is provided "AS IS," without a warranty of any kind. ALL 25 | * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING 26 | * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 27 | * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") 28 | * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 29 | * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 30 | * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 31 | * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 32 | * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 33 | * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 34 | * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 35 | * 36 | * You acknowledge that this software is not designed, licensed or intended 37 | * for use in the design, construction, operation or maintenance of any 38 | * nuclear facility. 39 | */ 40 | 41 | #ifndef POLARBEAR_THREADS_H 42 | #define POLARBEAR_THREADS_H 43 | 44 | 45 | #include "jvmti.h" 46 | #include "jni.h" 47 | 48 | #include "io.h" 49 | 50 | void JNICALL printThreadDump(jvmtiEnv *jvmti, JNIEnv *jni, Output *out, jthread current); 51 | 52 | struct ThreadSuspension { 53 | jvmtiEnv* jvmti; 54 | jthread current; 55 | jthread *threads; 56 | jvmtiError *errors; 57 | int changedCount; 58 | 59 | ThreadSuspension(jvmtiEnv *_jvmti, JNIEnv *jni); 60 | 61 | void resume(); 62 | 63 | ~ThreadSuspension(); 64 | }; 65 | 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * checks.h 3 | * 4 | * Originally based on http://hope.nyc.ny.us/~lprimak/java/demo/jvmti/heapViewer/ 5 | * 6 | * Original source is Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved. 7 | * 8 | * Modifications are Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 13 | * -Redistribution of source code must retain the above copyright notice, this 14 | * list of conditions and the following disclaimer. 15 | * 16 | * -Redistribution in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * 20 | * Neither the name of Sun Microsystems, Inc. or the names of contributors may 21 | * be used to endorse or promote products derived from this software without 22 | * specific prior written permission. 23 | * 24 | * This software is provided "AS IS," without a warranty of any kind. ALL 25 | * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING 26 | * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 27 | * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") 28 | * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 29 | * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 30 | * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 31 | * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 32 | * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 33 | * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 34 | * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 35 | * 36 | * You acknowledge that this software is not designed, licensed or intended 37 | * for use in the design, construction, operation or maintenance of any 38 | * nuclear facility. 39 | */ 40 | 41 | #ifndef POLARBEAR_BASE_H 42 | #define POLARBEAR_BASE_H 43 | 44 | 45 | #include "jvmti.h" 46 | 47 | 48 | /* Global static data */ 49 | typedef struct { 50 | jboolean vmDeathCalled; 51 | jboolean dumpInProgress; 52 | jrawMonitorID lock; 53 | int totalCount; 54 | 55 | char *optionsCopy; 56 | int retainedSizeClassCount; 57 | char **retainedSizeClasses; 58 | 59 | int shellSocket; 60 | int activeShellSocket; 61 | } GlobalData; 62 | 63 | extern GlobalData *gdata; 64 | 65 | 66 | void deallocate(jvmtiEnv *jvmti, void *p); 67 | 68 | /* Check for NULL pointer error */ 69 | #define CHECK_FOR_NULL(ptr) checkForNull(ptr, __FILE__, __LINE__) 70 | 71 | /* Check for JVMTI errors. */ 72 | #define CHECK(result) checkJvmtiError(jvmti, result, __FILE__, __LINE__) 73 | 74 | 75 | void checkForNull(void *ptr, const char *file, const int line); 76 | 77 | void checkJvmtiError(jvmtiEnv *jvmti, jvmtiError err, const char *file, const int line); 78 | 79 | 80 | /* Enter agent monitor protected section */ 81 | void enterAgentMonitor(jvmtiEnv *jvmti); 82 | 83 | 84 | /* Exit agent monitor protected section */ 85 | void exitAgentMonitor(jvmtiEnv *jvmti); 86 | 87 | 88 | #endif -------------------------------------------------------------------------------- /base.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * checks.cc 3 | * 4 | * Originally based on http://hope.nyc.ny.us/~lprimak/java/demo/jvmti/heapViewer/ 5 | * 6 | * Original source is Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved. 7 | * 8 | * Modifications are Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 13 | * -Redistribution of source code must retain the above copyright notice, this 14 | * list of conditions and the following disclaimer. 15 | * 16 | * -Redistribution in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * 20 | * Neither the name of Sun Microsystems, Inc. or the names of contributors may 21 | * be used to endorse or promote products derived from this software without 22 | * specific prior written permission. 23 | * 24 | * This software is provided "AS IS," without a warranty of any kind. ALL 25 | * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING 26 | * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 27 | * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") 28 | * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 29 | * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 30 | * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 31 | * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 32 | * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 33 | * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 34 | * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 35 | * 36 | * You acknowledge that this software is not designed, licensed or intended 37 | * for use in the design, construction, operation or maintenance of any 38 | * nuclear facility. 39 | */ 40 | 41 | #include "base.h" 42 | 43 | #include 44 | #include 45 | 46 | 47 | GlobalData globalData, *gdata = &globalData; 48 | 49 | 50 | 51 | /* Deallocate JVMTI memory */ 52 | void deallocate(jvmtiEnv *jvmti, void *p) { 53 | jvmtiError err = jvmti->Deallocate((unsigned char *)p); 54 | if (err != JVMTI_ERROR_NONE) { 55 | fprintf(stderr, "ERROR: JVMTI Deallocate error err=%d\n", err); 56 | abort(); 57 | } 58 | } 59 | 60 | 61 | /* Check for NULL pointer error */ 62 | #define CHECK_FOR_NULL(ptr) checkForNull(ptr, __FILE__, __LINE__) 63 | 64 | void checkForNull(void *ptr, const char *file, const int line) { 65 | if (ptr == NULL) { 66 | fprintf(stderr, "ERROR: NULL pointer error in %s:%d\n", file, line); 67 | abort(); 68 | } 69 | } 70 | 71 | 72 | /* Check for JVMTI errors. */ 73 | #define CHECK(result) checkJvmtiError(jvmti, result, __FILE__, __LINE__) 74 | 75 | static char * getErrorName(jvmtiEnv *jvmti, jvmtiError errnum) { 76 | jvmtiError err; 77 | char *name; 78 | 79 | err = jvmti->GetErrorName(errnum, &name); 80 | if (err != JVMTI_ERROR_NONE) { 81 | fprintf(stderr, "ERROR: JVMTI GetErrorName error err=%d\n", err); 82 | abort(); 83 | } 84 | return name; 85 | } 86 | 87 | void checkJvmtiError(jvmtiEnv *jvmti, jvmtiError err, const char *file, const int line) { 88 | if (err != JVMTI_ERROR_NONE) { 89 | char *name; 90 | 91 | name = getErrorName(jvmti, err); 92 | fprintf(stderr, "ERROR: JVMTI error err=%d(%s) in %s:%d\n", 93 | err, name, file, line); 94 | deallocate(jvmti, name); 95 | abort(); 96 | } 97 | } 98 | 99 | 100 | /* Enter agent monitor protected section */ 101 | void enterAgentMonitor(jvmtiEnv *jvmti) { 102 | CHECK(jvmti->RawMonitorEnter(gdata->lock)); 103 | } 104 | 105 | 106 | /* Exit agent monitor protected section */ 107 | void exitAgentMonitor(jvmtiEnv *jvmti) { 108 | CHECK(jvmti->RawMonitorExit(gdata->lock)); 109 | } 110 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # Source lists 2 | LIBNAME=outOfMemory 3 | SOURCES=outOfMemory.cc base.cc threads.cc agentthread.cc shell.cc io.cc memory.cc 4 | 5 | LINK.cxx = $(CXX) $(MY_CFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) 6 | 7 | # Solaris Sun C Compiler Version 5.5 8 | ifeq ($(OSNAME), solaris) 9 | # Sun Solaris Compiler options needed 10 | COMMON_FLAGS=-mt -xregs=no%appl -KPIC 11 | # Options that help find errors 12 | COMMON_FLAGS+= -Xa -v -xstrconst -xc99=%none 13 | # Check LIBARCH for any special compiler options 14 | LIBARCH=$(shell uname -p) 15 | ifeq ($(LIBARCH), sparc) 16 | COMMON_FLAGS+=-xarch=v8 17 | endif 18 | ifeq ($(LIBARCH), sparcv9) 19 | COMMON_FLAGS+=-xarch=v9 20 | endif 21 | ifeq ($(OPT), true) 22 | CXXFLAGS=-xO2 $(COMMON_FLAGS) 23 | else 24 | CXXFLAGS=-g $(COMMON_FLAGS) 25 | endif 26 | # Object files needed to create library 27 | OBJECTS=$(SOURCES:%.cc=%.o) 28 | # Library name and options needed to build it 29 | LIBRARY=lib$(LIBNAME).so 30 | LDFLAGS=-z defs -ztext 31 | # Libraries we are dependent on 32 | LIBRARIES= -lc 33 | # Building a shared library 34 | LINK_SHARED=$(LINK.cxx) -G -o $@ 35 | endif 36 | 37 | # Linux GNU C Compiler 38 | ifeq ($(OSNAME), linux) 39 | # GNU Compiler options needed to build it 40 | COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer 41 | # Options that help find errors 42 | COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses 43 | ifeq ($(OPT), true) 44 | CXXFLAGS=-O2 $(COMMON_FLAGS) 45 | else 46 | CXXFLAGS=-g $(COMMON_FLAGS) 47 | endif 48 | # Object files needed to create library 49 | OBJECTS=$(SOURCES:%.cc=%.o) 50 | # Library name and options needed to build it 51 | LIBRARY=lib$(LIBNAME).so 52 | LDFLAGS=-Wl,-soname=$(LIBRARY) -static-libgcc -mimpure-text 53 | # Libraries we are dependent on 54 | LIBRARIES=-lc 55 | # Building a shared library 56 | LINK_SHARED=$(LINK.cxx) -shared -o $@ 57 | endif 58 | 59 | # Mac OSX 60 | ifeq ($(OSNAME), darwin) 61 | # GNU Compiler options needed to build it 62 | COMMON_FLAGS=-fno-strict-aliasing -fPIC -fno-omit-frame-pointer 63 | # Options that help find errors 64 | COMMON_FLAGS+= -W -Wall -Wno-unused -Wno-parentheses 65 | ifeq ($(OPT), true) 66 | CXXFLAGS=-O2 $(COMMON_FLAGS) 67 | else 68 | CXXFLAGS=-g $(COMMON_FLAGS) 69 | endif 70 | # Object files needed to create library 71 | OBJECTS=$(SOURCES:%.cc=%.o) 72 | # Library name and options needed to build it 73 | LIBRARY=lib$(LIBNAME).jnilib 74 | LDFLAGS=-Wl-static-libgcc -mimpure-text 75 | # Libraries we are dependent on 76 | LIBRARIES=-lc 77 | # Building a shared library 78 | LINK_SHARED=$(LINK.cxx) -dynamiclib -single_module -undefined suppress -flat_namespace -o $(LIBRARY) 79 | endif 80 | 81 | # Windows Microsoft C/C++ Optimizing Compiler Version 12 82 | ifeq ($(OSNAME), win32) 83 | CC=cl 84 | # Compiler options needed to build it 85 | COMMON_FLAGS=-Gy 86 | # Options that help find errors 87 | COMMON_FLAGS+=-W0 -WX 88 | ifeq ($(OPT), true) 89 | CXXFLAGS= -Ox -Op -Zi $(COMMON_FLAGS) 90 | else 91 | CXXFLAGS= -Od -Zi $(COMMON_FLAGS) 92 | endif 93 | # Object files needed to create library 94 | OBJECTS=$(SOURCES:%.cc=%.obj) 95 | # Library name and options needed to build it 96 | LIBRARY=$(LIBNAME).dll 97 | LDFLAGS= 98 | # Libraries we are dependent on 99 | LIBRARIES= 100 | # Building a shared library 101 | LINK_SHARED=link -dll -out:$@ 102 | endif 103 | 104 | # Common -I options 105 | CXXFLAGS += -I. 106 | CXXFLAGS += -I$(J2SDK)/include -I$(J2SDK)/include/$(OSNAME) 107 | 108 | %.class: %.java 109 | javac $< 110 | 111 | # Default rule 112 | all: $(LIBRARY) 113 | 114 | # Build native library 115 | $(LIBRARY): $(OBJECTS) 116 | $(LINK_SHARED) $(OBJECTS) $(LIBRARIES) 117 | 118 | # Cleanup the built bits 119 | clean: 120 | rm -f $(LIBRARY) $(OBJECTS) 121 | 122 | # Simple tester 123 | test: all Test.class 124 | rm -f /tmp/oom.log 125 | LD_LIBRARY_PATH=`pwd` $(J2SDK)/bin/java -Xms50m -Xmx50m -agentlib:$(LIBNAME)=HashMap,OOMList Test || cat '/tmp/oom.log' 126 | 127 | # Compilation rule only needed on Windows 128 | ifeq ($(OSNAME), win32) 129 | %.obj: %.cc 130 | $(COMPILE.c) $< 131 | endif 132 | 133 | -------------------------------------------------------------------------------- /shell.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * shell.cc 3 | * 4 | * Original source is Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "base.h" 29 | #include "io.h" 30 | #include "memory.h" 31 | #include "shell.h" 32 | #include "threads.h" 33 | 34 | 35 | static void interact(jvmtiEnv* jvmti, JNIEnv* jni, int socket); 36 | 37 | 38 | // Starts the shell server. 39 | void JNICALL shellServer(jvmtiEnv* jvmti, JNIEnv* jni, void *pData) { 40 | struct sockaddr_in serverInfo; 41 | 42 | // TCP stream oriented socket. 43 | gdata->activeShellSocket = -1; 44 | gdata->shellSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 45 | 46 | if (gdata->shellSocket == -1) { 47 | fprintf(stderr, "Could not create a socket for listening"); 48 | return; 49 | } 50 | 51 | int optval = 1; 52 | setsockopt(gdata->shellSocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); 53 | 54 | serverInfo.sin_family = AF_INET; 55 | serverInfo.sin_addr.s_addr = INADDR_ANY; 56 | serverInfo.sin_port = htons((short) 8787); 57 | 58 | // Bind the socket to our local server address 59 | int nret = bind(gdata->shellSocket, (struct sockaddr *)&serverInfo, sizeof(serverInfo)); 60 | 61 | if (nret == -1) { 62 | fprintf(stderr, "Could not bind the control socket on port 8787."); 63 | return; 64 | } 65 | 66 | // Make the socket listen 67 | nret = listen(gdata->shellSocket, 1); 68 | if (nret == -1) { 69 | fprintf(stderr, "Error listening on socket on port 8787."); 70 | return; 71 | } 72 | 73 | int sockd = 0; 74 | while ((sockd = accept(gdata->shellSocket, NULL, NULL)) != -1) { 75 | interact(jvmti, jni, sockd); 76 | } 77 | 78 | enterAgentMonitor(jvmti); { 79 | closeShellServer(); 80 | } exitAgentMonitor(jvmti); 81 | } 82 | 83 | 84 | void closeShellSession() { 85 | if (gdata->activeShellSocket != -1) { 86 | if (close(gdata->activeShellSocket) == -1) { 87 | fprintf(stderr, "Error closing active session."); 88 | } 89 | gdata->activeShellSocket = -1; 90 | } 91 | } 92 | 93 | 94 | void closeShellServer() { 95 | closeShellSession(); 96 | if (gdata->shellSocket != -1) { 97 | if (close(gdata->shellSocket) == -1) { 98 | fprintf(stderr, "Error closing socket."); 99 | } 100 | gdata->shellSocket = -1; 101 | } 102 | } 103 | 104 | 105 | 106 | #define MAX_LINE 1000 107 | 108 | 109 | ssize_t readline(int sockd, char *vptr, int maxlen) { 110 | int rc; 111 | char c, *buffer; 112 | 113 | buffer = vptr; 114 | 115 | int n; 116 | for (n = 1; n < maxlen; n++) { 117 | if ((rc = read(sockd, &c, 1)) == 1) { 118 | if (c == '\r') { 119 | n -= 1; 120 | continue; 121 | } 122 | if (c == '\n') { 123 | break; 124 | } 125 | *buffer++ = c; 126 | 127 | } else if (rc == 0) { 128 | if (n == 1) { 129 | return 0; 130 | } else { 131 | break; 132 | } 133 | 134 | } else { 135 | if (errno == EINTR) { 136 | continue; 137 | } 138 | return -1; 139 | } 140 | } 141 | 142 | *buffer = 0; 143 | return n; 144 | } 145 | 146 | 147 | ssize_t writestring(int sockd, const char *vptr, size_t n) { 148 | int nwritten; 149 | const char *buffer = vptr; 150 | int nleft = n; 151 | 152 | while (nleft > 0) { 153 | if ((nwritten = write(sockd, buffer, nleft)) <= 0) { 154 | if (errno == EINTR) { 155 | nwritten = 0; 156 | } else { 157 | return -1; 158 | } 159 | } 160 | nleft -= nwritten; 161 | buffer += nwritten; 162 | } 163 | 164 | return n; 165 | } 166 | 167 | 168 | static void interact(jvmtiEnv* jvmti, JNIEnv* jni, int socket) { 169 | char buffer[1000]; 170 | SocketOutput out(socket); 171 | out.printf("Type 'help' to see a list of commands.\n"); 172 | 173 | gdata->activeShellSocket = socket; 174 | 175 | while (1) { 176 | out.printf("> "); 177 | 178 | int length = readline(socket, buffer, MAX_LINE - 1); 179 | if (length < 0) { 180 | break; 181 | } 182 | if (strcmp("quit", buffer) == 0) { 183 | out.printf("Goodbye\n"); 184 | break; 185 | } 186 | if (strcmp("help", buffer) == 0) { 187 | out.printf("Try any of the following:\n\n"); 188 | out.printf("threads"); 189 | out.printf("histogram"); 190 | out.printf("gc"); 191 | out.printf("stats "); 192 | out.printf("count "); 193 | out.printf("referrers "); 194 | 195 | } else if (strcmp("threads", buffer) == 0) { 196 | enterAgentMonitor(jvmti); { 197 | 198 | printThreadDump(jvmti, jni, &out, (jthread) 0); 199 | 200 | } exitAgentMonitor(jvmti); 201 | 202 | } else if (strcmp("histogram", buffer) == 0) { 203 | enterAgentMonitor(jvmti); { 204 | 205 | printHistogram(jvmti, &out, false); 206 | 207 | } exitAgentMonitor(jvmti); 208 | 209 | } else if (strncmp("count ", buffer, 6) == 0) { 210 | enterAgentMonitor(jvmti); { 211 | ThreadSuspension threads(jvmti, jni); 212 | 213 | out.printf("Computing count of '%s'\n\n", buffer + 6); 214 | printClassStats(jvmti, buffer + 6, &out, false); 215 | 216 | } exitAgentMonitor(jvmti); 217 | 218 | } else if (strncmp("stats ", buffer, 6) == 0) { 219 | enterAgentMonitor(jvmti); { 220 | ThreadSuspension threads(jvmti, jni); 221 | 222 | out.printf("Computing stats for '%s'\n\n", buffer + 6); 223 | printClassStats(jvmti, buffer + 6, &out, true); 224 | 225 | } exitAgentMonitor(jvmti); 226 | 227 | } else if (strncmp("referrers ", buffer, 10) == 0) { 228 | enterAgentMonitor(jvmti); { 229 | ThreadSuspension threads(jvmti, jni); 230 | 231 | out.printf("Computing stats for '%s'\n\n", buffer + 10); 232 | printReferrers(jvmti, buffer + 10, &out); 233 | 234 | } exitAgentMonitor(jvmti); 235 | 236 | 237 | } else if (strcmp("gc", buffer) == 0) { 238 | enterAgentMonitor(jvmti); { 239 | out.printf("Forcing garbage collection.\n"); 240 | CHECK(jvmti->ForceGarbageCollection()); 241 | } exitAgentMonitor(jvmti); 242 | 243 | } else { 244 | out.printf("Unknown command: '%s'\n", buffer); 245 | } 246 | } 247 | 248 | enterAgentMonitor(jvmti); { 249 | closeShellSession(); 250 | } exitAgentMonitor(jvmti); 251 | } 252 | -------------------------------------------------------------------------------- /outOfMemory.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * outOfMemory.cc 3 | * 4 | * Originally based on http://hope.nyc.ny.us/~lprimak/java/demo/jvmti/heapViewer/ 5 | * 6 | * Original source is Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved. 7 | * 8 | * Modifications are Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 13 | * -Redistribution of source code must retain the above copyright notice, this 14 | * list of conditions and the following disclaimer. 15 | * 16 | * -Redistribution in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * 20 | * Neither the name of Sun Microsystems, Inc. or the names of contributors may 21 | * be used to endorse or promote products derived from this software without 22 | * specific prior written permission. 23 | * 24 | * This software is provided "AS IS," without a warranty of any kind. ALL 25 | * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING 26 | * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 27 | * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") 28 | * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 29 | * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 30 | * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 31 | * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 32 | * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 33 | * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 34 | * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 35 | * 36 | * You acknowledge that this software is not designed, licensed or intended 37 | * for use in the design, construction, operation or maintenance of any 38 | * nuclear facility. 39 | */ 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "jni.h" 47 | #include "jvmti.h" 48 | 49 | #include "agentthread.h" 50 | #include "base.h" 51 | #include "io.h" 52 | #include "memory.h" 53 | #include "shell.h" 54 | #include "threads.h" 55 | 56 | 57 | /* Called when memory is exhausted. */ 58 | static void JNICALL resourceExhausted( 59 | jvmtiEnv *jvmti, JNIEnv* jni, jint flags, const void* reserved, const char* description) { 60 | if (flags & 0x0003) { 61 | enterAgentMonitor(jvmti); { 62 | FILE * out = fopen("/tmp/oom.log", "a"); 63 | FileOutput output(out); 64 | 65 | output.printf("About to throw an OutOfMemory error.\n"); 66 | 67 | output.printf("Suspending all threads except the current one.\n"); 68 | 69 | ThreadSuspension threads(jvmti, jni); 70 | 71 | output.printf("Printing a heap histogram.\n"); 72 | 73 | printHistogram(jvmti, &output, true); 74 | 75 | output.printf("Resuming threads.\n"); 76 | 77 | threads.resume(); 78 | 79 | output.printf("Printing thread dump.\n"); 80 | 81 | if (!gdata->vmDeathCalled) { 82 | printThreadDump(jvmti, jni, &output, threads.current); 83 | } 84 | output.printf("\n\n"); 85 | fclose(out); 86 | } exitAgentMonitor(jvmti); 87 | } 88 | } 89 | 90 | 91 | /* Callback to init the module. */ 92 | static void JNICALL vmInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread) 93 | { 94 | enterAgentMonitor(jvmti); { 95 | jvmtiError err; 96 | 97 | createAgentThread(jvmti, env, shellServer, NULL); 98 | 99 | CHECK(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, NULL)); 100 | } exitAgentMonitor(jvmti); 101 | } 102 | 103 | 104 | /* Callback for JVM death. */ 105 | static void JNICALL vmDeath(jvmtiEnv *jvmti, JNIEnv *env) { 106 | jvmtiError err; 107 | 108 | /* Disable events */ 109 | enterAgentMonitor(jvmti); { 110 | CHECK(jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_RESOURCE_EXHAUSTED, NULL)); 111 | 112 | closeShellServer(); 113 | 114 | gdata->vmDeathCalled = JNI_TRUE; 115 | } exitAgentMonitor(jvmti); 116 | } 117 | 118 | 119 | /* Called by the JVM to load the module. */ 120 | JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { 121 | jint rc; 122 | jvmtiError err; 123 | jvmtiCapabilities capabilities; 124 | jvmtiEventCallbacks callbacks; 125 | jvmtiEnv *jvmti; 126 | FILE *log; 127 | 128 | /* Build list of filter classes. */ 129 | if (options && options[0]) { 130 | int len = strlen(options); 131 | int commaCount = 0; 132 | gdata->optionsCopy = strdup(options); 133 | for (int i = 0; i < len; i++) { 134 | if (options[i] == ',') { 135 | commaCount += 1; 136 | } 137 | } 138 | gdata->retainedSizeClassCount = commaCount + 1; 139 | if (commaCount == 0) { 140 | gdata->retainedSizeClasses = &gdata->optionsCopy; 141 | } else { 142 | gdata->retainedSizeClasses = (char **) calloc(sizeof(char *), gdata->retainedSizeClassCount); 143 | char *base = gdata->optionsCopy; 144 | int j = 0; 145 | for (int i = 0; i < len; i++) { 146 | if (gdata->optionsCopy[i] == ',') { 147 | gdata->optionsCopy[i] = 0; 148 | gdata->retainedSizeClasses[j] = base; 149 | base = gdata->optionsCopy + (i + 1); 150 | j++; 151 | } 152 | } 153 | gdata->retainedSizeClasses[j] = base; 154 | } 155 | } else { 156 | gdata->retainedSizeClassCount = 0; 157 | } 158 | 159 | log = fopen("/tmp/oom.log", "a"); 160 | fprintf(log, "Initializing polarbear.\n\n"); 161 | 162 | if (gdata->retainedSizeClassCount) { 163 | fprintf(log, "Performing retained size analysis for %d classes:\n", gdata->retainedSizeClassCount); 164 | for (int i = 0; i < gdata->retainedSizeClassCount; i++) { 165 | fprintf(log, "%s\n", gdata->retainedSizeClasses[i]); 166 | } 167 | fprintf(log, "\n"); 168 | } 169 | 170 | /* Get JVMTI environment */ 171 | jvmti = NULL; 172 | rc = vm->GetEnv((void **)&jvmti, JVMTI_VERSION); 173 | if (rc != JNI_OK) { 174 | fprintf(stderr, "ERROR: Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc); 175 | return -1; 176 | } 177 | CHECK_FOR_NULL(jvmti); 178 | 179 | /* Get/Add JVMTI capabilities */ 180 | CHECK(jvmti->GetCapabilities(&capabilities)); 181 | capabilities.can_tag_objects = 1; 182 | capabilities.can_generate_garbage_collection_events = 1; 183 | capabilities.can_get_source_file_name = 1; 184 | capabilities.can_get_line_numbers = 1; 185 | capabilities.can_suspend = 1; 186 | CHECK(jvmti->AddCapabilities(&capabilities)); 187 | 188 | /* Create the raw monitor */ 189 | CHECK(jvmti->CreateRawMonitor("agent lock", &(gdata->lock))); 190 | 191 | /* Set callbacks and enable event notifications */ 192 | memset(&callbacks, 0, sizeof(callbacks)); 193 | callbacks.VMInit = &vmInit; 194 | callbacks.VMDeath = &vmDeath; 195 | callbacks.ResourceExhausted = resourceExhausted; 196 | CHECK(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks))); 197 | CHECK(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL)); 198 | CHECK(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL)); 199 | CHECK(jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_RESOURCE_EXHAUSTED, NULL)); 200 | 201 | fclose(log); 202 | 203 | return 0; 204 | } 205 | 206 | /* Agent_OnUnload() is called last */ 207 | JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) { 208 | } 209 | -------------------------------------------------------------------------------- /threads.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * threads.cc 3 | * 4 | * Originally based on http://hope.nyc.ny.us/~lprimak/java/demo/jvmti/heapViewer/ 5 | * 6 | * Original source is Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved. 7 | * 8 | * Modifications are Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 13 | * -Redistribution of source code must retain the above copyright notice, this 14 | * list of conditions and the following disclaimer. 15 | * 16 | * -Redistribution in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * 20 | * Neither the name of Sun Microsystems, Inc. or the names of contributors may 21 | * be used to endorse or promote products derived from this software without 22 | * specific prior written permission. 23 | * 24 | * This software is provided "AS IS," without a warranty of any kind. ALL 25 | * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING 26 | * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 27 | * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") 28 | * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 29 | * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 30 | * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 31 | * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 32 | * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 33 | * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 34 | * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 35 | * 36 | * You acknowledge that this software is not designed, licensed or intended 37 | * for use in the design, construction, operation or maintenance of any 38 | * nuclear facility. 39 | */ 40 | 41 | #include 42 | #include 43 | 44 | #include "base.h" 45 | #include "threads.h" 46 | 47 | 48 | /* Prints a thread frame. */ 49 | static void JNICALL printFrame(jvmtiEnv* jvmti, jvmtiFrameInfo frame, Output *out) { 50 | jvmtiError err; 51 | char *methodName, *className, *cleanClassName; 52 | char *fileName; 53 | int si, li, lineNumber; 54 | jclass declaringClass; 55 | jint locationCount; 56 | jvmtiLineNumberEntry* locationTable; 57 | 58 | CHECK(jvmti->GetMethodName(frame.method, &methodName, NULL, NULL)); 59 | CHECK(jvmti->GetMethodDeclaringClass(frame.method, &declaringClass)); 60 | CHECK(jvmti->GetClassSignature(declaringClass, &className, NULL)); 61 | err = jvmti->GetSourceFileName(declaringClass, &fileName); 62 | if (err == JVMTI_ERROR_NATIVE_METHOD || err == JVMTI_ERROR_ABSENT_INFORMATION) { 63 | fileName = strdup("Unknown"); 64 | 65 | } else { 66 | char *temp; 67 | 68 | CHECK(err); 69 | temp = strdup(fileName); 70 | deallocate(jvmti, fileName); 71 | fileName = temp; 72 | } 73 | err = jvmti->GetLineNumberTable(frame.method, &locationCount, &locationTable); 74 | if (err == JVMTI_ERROR_NATIVE_METHOD || err == JVMTI_ERROR_ABSENT_INFORMATION) { 75 | lineNumber = 0; 76 | } else { 77 | CHECK(err); 78 | lineNumber = 0; 79 | for (li = 0; li < locationCount; li++) { 80 | if (locationTable[li].start_location > frame.location) { 81 | break; 82 | } 83 | lineNumber = locationTable[li].line_number; 84 | } 85 | deallocate(jvmti, locationTable); 86 | } 87 | 88 | cleanClassName = strdup(className + 1); 89 | si = 0; 90 | while (cleanClassName[si]) { 91 | if (cleanClassName[si] == '/') { 92 | cleanClassName[si] = '.'; 93 | } else if (cleanClassName[si] == ';') { 94 | cleanClassName[si] = '.'; 95 | } 96 | si++; 97 | } 98 | 99 | if (lineNumber) { 100 | out->printf( "\tat %s%s(%s:%d)\n", cleanClassName, methodName, fileName, lineNumber); 101 | } else { 102 | out->printf( "\tat %s%s(%s)\n", cleanClassName, methodName, fileName); 103 | } 104 | deallocate(jvmti, methodName); 105 | deallocate(jvmti, className); 106 | free(fileName); 107 | free(cleanClassName); 108 | } 109 | 110 | 111 | /* Prints a thread dump. */ 112 | void JNICALL printThreadDump(jvmtiEnv *jvmti, JNIEnv *jni, Output *out, jthread current) { 113 | jvmtiStackInfo *stack_info; 114 | jint thread_count; 115 | int ti; 116 | jvmtiError err; 117 | jvmtiThreadInfo threadInfo; 118 | 119 | out->printf( "\n"); 120 | CHECK(jvmti->GetAllStackTraces(150, &stack_info, &thread_count)); 121 | out->printf( "Dumping thread state for %d threads\n\n", thread_count); 122 | for (ti = 0; ti < thread_count; ++ti) { 123 | jvmtiStackInfo *infop = &stack_info[ti]; 124 | jthread thread = infop->thread; 125 | jint state = infop->state; 126 | jvmtiFrameInfo *frames = infop->frame_buffer; 127 | int fi; 128 | const char *threadState; 129 | 130 | if (state & JVMTI_THREAD_STATE_SUSPENDED) { 131 | threadState = "SUSPENDED"; 132 | } else if (state & JVMTI_THREAD_STATE_INTERRUPTED) { 133 | threadState = "INTERRUPTED"; 134 | } else if (state & JVMTI_THREAD_STATE_IN_NATIVE) { 135 | threadState = "NATIVE"; 136 | } else if (state & JVMTI_THREAD_STATE_RUNNABLE) { 137 | threadState = "RUNNABLE"; 138 | } else if (state & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) { 139 | threadState = "BLOCKED"; 140 | } else if (state & JVMTI_THREAD_STATE_IN_OBJECT_WAIT) { 141 | threadState = "WAITING"; 142 | } else if (state & JVMTI_THREAD_STATE_PARKED) { 143 | threadState = "PARKED"; 144 | } else if (state & JVMTI_THREAD_STATE_SLEEPING) { 145 | threadState = "SLEEPING"; 146 | } else { 147 | threadState = "UNKNOWN"; 148 | } 149 | 150 | jvmti->GetThreadInfo(thread, &threadInfo); 151 | out->printf( "#%d - %s - %s", ti + 1, threadInfo.name, threadState); 152 | if (thread == current || jni->IsSameObject(thread, current)) { 153 | out->printf( " - [OOM thrower]"); 154 | } 155 | out->printf( "\n"); 156 | deallocate(jvmti, threadInfo.name); 157 | 158 | for (fi = 0; fi < infop->frame_count; fi++) { 159 | printFrame(jvmti, frames[fi], out); 160 | } 161 | out->printf( "\n"); 162 | } 163 | out->printf( "\n\n"); 164 | /* this one Deallocate call frees all data allocated by GetAllStackTraces */ 165 | deallocate(jvmti, stack_info); 166 | } 167 | 168 | 169 | ThreadSuspension::ThreadSuspension(jvmtiEnv *_jvmti, JNIEnv *jni) : jvmti(_jvmti) { 170 | CHECK(_jvmti->GetCurrentThread(&this->current)); 171 | 172 | jint threadCount; 173 | CHECK(_jvmti->GetAllThreads(&threadCount, &this->threads)); 174 | 175 | int j = 0; 176 | for (int i = 0; i < threadCount; i++) { 177 | if (!jni->IsSameObject(this->threads[i], this->current)) { 178 | this->threads[j] = this->threads[i]; 179 | j++; 180 | } 181 | } 182 | 183 | this->errors = (jvmtiError *)calloc(sizeof(jvmtiError), j); 184 | CHECK(_jvmti->SuspendThreadList(j, threads, this->errors)); 185 | this->changedCount = j; 186 | } 187 | 188 | 189 | void ThreadSuspension::resume() { 190 | int j; 191 | if (this->threads) { 192 | for (int i = 0; i < this->changedCount; i++) { 193 | if (!this->errors[i]) { 194 | CHECK(this->jvmti->ResumeThread(threads[i])); 195 | } 196 | } 197 | free(this->errors); 198 | deallocate(this->jvmti, this->threads); 199 | this->threads = 0; 200 | } 201 | } 202 | 203 | ThreadSuspension::~ThreadSuspension() { 204 | this->resume(); 205 | } 206 | -------------------------------------------------------------------------------- /memory.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * memory.cc 3 | * 4 | * Originally based on http://hope.nyc.ny.us/~lprimak/java/demo/jvmti/heapViewer/ 5 | * 6 | * Original source is Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved. 7 | * 8 | * Modifications are Copyright (c) 2011 The PolarBear Authors. All Rights Reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 13 | * -Redistribution of source code must retain the above copyright notice, this 14 | * list of conditions and the following disclaimer. 15 | * 16 | * -Redistribution in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * 20 | * Neither the name of Sun Microsystems, Inc. or the names of contributors may 21 | * be used to endorse or promote products derived from this software without 22 | * specific prior written permission. 23 | * 24 | * This software is provided "AS IS," without a warranty of any kind. ALL 25 | * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING 26 | * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 27 | * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") 28 | * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE 29 | * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 30 | * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 31 | * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 32 | * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 33 | * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 34 | * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 35 | * 36 | * You acknowledge that this software is not designed, licensed or intended 37 | * for use in the design, construction, operation or maintenance of any 38 | * nuclear facility. 39 | */ 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "jni.h" 47 | #include "jvmti.h" 48 | 49 | #include "base.h" 50 | #include "io.h" 51 | #include "memory.h" 52 | 53 | 54 | /* Typedef to hold class details */ 55 | typedef struct { 56 | jclass klass; 57 | char *signature; 58 | int count; 59 | int referLevelCount[4]; 60 | int space; 61 | } ClassDetails; 62 | 63 | #define REFER_DEPTH 3 64 | 65 | 66 | struct AllClassDetails { 67 | jvmtiEnv *jvmti; 68 | ClassDetails *details; 69 | jclass *classes; 70 | jint count; 71 | 72 | AllClassDetails(jvmtiEnv *_jvmti) : jvmti(_jvmti) { 73 | /* Get all the loaded classes */ 74 | CHECK(_jvmti->GetLoadedClasses(&this->count, &this->classes)); 75 | 76 | /* Setup an area to hold details about these classes */ 77 | this->details = (ClassDetails*)calloc(sizeof(ClassDetails), this->count); 78 | CHECK_FOR_NULL(this->details); 79 | 80 | jint i; 81 | for (i = 0 ; i < this->count ; i++) { 82 | char *sig; 83 | 84 | /* Get and save the class signature */ 85 | CHECK(_jvmti->GetClassSignature(this->classes[i], &sig, NULL)); 86 | CHECK_FOR_NULL(sig); 87 | this->details[i].signature = strdup(sig); 88 | deallocate(_jvmti, sig); 89 | 90 | this->details[i].klass = this->classes[i]; 91 | 92 | /* Tag this jclass */ 93 | CHECK(_jvmti->SetTag(this->classes[i], (jlong)(ptrdiff_t)(void*)(&this->details[i]))); 94 | } 95 | } 96 | 97 | ~AllClassDetails() { 98 | jint i; 99 | 100 | deallocate(this->jvmti, this->classes); 101 | for (i = 0 ; i < this->count ; i++) { 102 | if (this->details[i].signature != NULL) { 103 | free(this->details[i].signature); 104 | } 105 | } 106 | free(this->details); 107 | } 108 | 109 | jint getSignatureOffset(const char * signature) { 110 | for (jint offset = 0 ; offset < this->count; offset++) { 111 | ClassDetails d = this->details[offset]; 112 | if (d.signature != 0 && strcmp(d.signature, signature) == 0) { 113 | return offset; 114 | } 115 | } 116 | return -1; 117 | } 118 | }; 119 | 120 | 121 | /* Test if the given haystack ends with the given needle + skipHaystackChars ignored characters. */ 122 | static bool endswith(char *haystack, char *needle, int skipHaystackChars) { 123 | int hLen = strlen(haystack); 124 | int nLen = strlen(needle); 125 | 126 | int offset = hLen - nLen - skipHaystackChars; 127 | if (offset < 0) { 128 | return false; 129 | } 130 | 131 | for (int i = nLen - 1; i >= 0; i--) { 132 | if (haystack[i + offset] != needle[i]) { 133 | return false; 134 | } 135 | } 136 | 137 | return true; 138 | } 139 | 140 | 141 | /* IterateThroughHeap callback that finds referrers to a given class. */ 142 | static jint JNICALL referenceFinder( 143 | jvmtiHeapReferenceKind reference_kind, 144 | const jvmtiHeapReferenceInfo* reference_info, 145 | jlong class_tag, 146 | jlong referrer_class_tag, 147 | jlong size, 148 | jlong* tag_ptr, 149 | jlong* referrer_tag_ptr, 150 | jint length, 151 | void* user_data) { 152 | if (referrer_tag_ptr) { 153 | if (class_tag == (jlong) user_data) { 154 | *referrer_tag_ptr = 1; 155 | } 156 | } 157 | return JVMTI_VISIT_OBJECTS; 158 | } 159 | 160 | 161 | /* IterateThroughHeap callback that finds shortest path from an object to an object of the given class. */ 162 | static jint JNICALL referenceDepthCounter( 163 | jvmtiHeapReferenceKind reference_kind, 164 | const jvmtiHeapReferenceInfo* reference_info, 165 | jlong class_tag, 166 | jlong referrer_class_tag, 167 | jlong size, 168 | jlong* tag_ptr, 169 | jlong* referrer_tag_ptr, 170 | jint length, 171 | void* user_data) { 172 | if (referrer_tag_ptr) { 173 | if (*tag_ptr) { 174 | if (*referrer_tag_ptr == 0 || (*tag_ptr + 1) < *referrer_tag_ptr) { 175 | *referrer_tag_ptr = *tag_ptr + 1; 176 | } 177 | } 178 | } 179 | return JVMTI_VISIT_OBJECTS; 180 | } 181 | 182 | 183 | /* Aggregates reference depth tags by class. */ 184 | static jint JNICALL referenceDepthAggregator( 185 | jlong class_tag, 186 | jlong size, 187 | jlong* tag_ptr, 188 | jint length, 189 | void* user_data) { 190 | if (tag_ptr && *tag_ptr && *tag_ptr <= REFER_DEPTH) { 191 | ClassDetails *d = (ClassDetails*)(void*)(ptrdiff_t)class_tag; 192 | d->referLevelCount[*tag_ptr - 1] += 1; 193 | } 194 | 195 | return JVMTI_VISIT_OBJECTS; 196 | } 197 | 198 | 199 | /* Set up pointers / tag relationships for the given ClassDetails objects. */ 200 | static void setTagPointers(jvmtiEnv *jvmti, ClassDetails *details, int classCount) { 201 | /* Ensure classes are tagged correctly. */ 202 | for (int i = 0 ; i < classCount; i++) { 203 | /* Tag this jclass */ 204 | CHECK(jvmti->SetTag(details[i].klass, (jlong)(ptrdiff_t)(void *)(&details[i]))); 205 | } 206 | } 207 | 208 | 209 | /* IterateThroughHeap callback that clears tags. */ 210 | static jint JNICALL clearTag(jlong class_tag, jlong size, jlong* tag_ptr, jint length, void* user_data) { 211 | *tag_ptr = 0; 212 | return JVMTI_VISIT_OBJECTS; 213 | } 214 | 215 | 216 | /* Clear all tags. */ 217 | static void clearTags(jvmtiEnv *jvmti) { 218 | jvmtiHeapCallbacks callbacks; 219 | memset(&callbacks, 0, sizeof(callbacks)); 220 | 221 | callbacks.heap_iteration_callback = clearTag; 222 | CHECK(jvmti->IterateThroughHeap((jint) 0, (jclass) 0, &callbacks, (void *) NULL)); 223 | } 224 | 225 | 226 | /* IterateThroughHeap callback that sets a tag to 1. */ 227 | static jint JNICALL setTag(jlong class_tag, jlong size, jlong* tag_ptr, jint length, void* user_data) { 228 | *tag_ptr = 1; 229 | return JVMTI_VISIT_OBJECTS; 230 | } 231 | 232 | 233 | /* IterateThroughHeap callback that marks all elements of the given class. */ 234 | static void mark(jvmtiEnv *jvmti, jclass klass) { 235 | jvmtiHeapCallbacks callbacks; 236 | memset(&callbacks, 0, sizeof(callbacks)); 237 | callbacks.heap_iteration_callback = setTag; 238 | CHECK(jvmti->IterateThroughHeap((jint) 0, klass, &callbacks, (void *) NULL)); 239 | } 240 | 241 | 242 | /* IterateThroughHeap callback that propogates marking from one set of objects to all referenced objects. */ 243 | static jint JNICALL markReferences( 244 | jvmtiHeapReferenceKind reference_kind, 245 | const jvmtiHeapReferenceInfo* reference_info, 246 | jlong class_tag, 247 | jlong referrer_class_tag, 248 | jlong size, 249 | jlong* tag_ptr, 250 | jlong* referrer_tag_ptr, 251 | jint length, 252 | void* user_data) { 253 | if (referrer_tag_ptr && *referrer_tag_ptr && *tag_ptr == 0) { 254 | *tag_ptr = 1; 255 | } 256 | return JVMTI_VISIT_OBJECTS; 257 | } 258 | 259 | 260 | /* IterateThroughHeap callback that accumulates sizes of marked objects. */ 261 | static jint JNICALL addSizes(jlong class_tag, jlong size, jlong* tag_ptr, jint length, void* user_data) { 262 | *((long *) user_data) += size; 263 | return JVMTI_VISIT_OBJECTS; 264 | } 265 | 266 | 267 | /* Gets the retained size across all instances of a given class and all objects referenced by those objects. */ 268 | static long getRetainedSize(jvmtiEnv *jvmti, jclass klass) { 269 | clearTags(jvmti); 270 | 271 | mark(jvmti, klass); 272 | 273 | jvmtiHeapCallbacks callbacks; 274 | memset(&callbacks, 0, sizeof(callbacks)); 275 | callbacks.heap_reference_callback = markReferences; 276 | 277 | CHECK(jvmti->FollowReferences(0, NULL, NULL, &callbacks, 0)); 278 | 279 | long result = 0; 280 | callbacks.heap_iteration_callback = addSizes; 281 | CHECK(jvmti->IterateThroughHeap(JVMTI_HEAP_FILTER_UNTAGGED, 0, &callbacks, (void *)(&result))); 282 | 283 | return result; 284 | } 285 | 286 | 287 | /* Prints a referrer summary. */ 288 | static void printRefererSummary(jvmtiEnv *jvmti, Output *out, ClassDetails* details, int classCount, int offset) { 289 | jvmtiHeapCallbacks callbacks; 290 | memset(&callbacks, 0, sizeof(callbacks)); 291 | 292 | clearTags(jvmti); 293 | setTagPointers(jvmti, details, classCount); 294 | 295 | callbacks.heap_reference_callback = referenceFinder; 296 | CHECK(jvmti->FollowReferences(0, NULL, NULL, &callbacks, (void *)(&details[offset]))); 297 | 298 | callbacks.heap_reference_callback = referenceDepthCounter; 299 | for (int i = 0; i < REFER_DEPTH - 1; i++) { 300 | CHECK(jvmti->FollowReferences(0, NULL, NULL, &callbacks, 0)); 301 | } 302 | 303 | setTagPointers(jvmti, details, classCount); 304 | callbacks.heap_iteration_callback = referenceDepthAggregator; 305 | CHECK(jvmti->IterateThroughHeap((jint) 0, (jclass) 0, &callbacks, (void *) NULL)); 306 | 307 | out->printf("\n"); 308 | for (int level = 0; level < REFER_DEPTH; level++) { 309 | out->printf("\t\tLevel %d referrers:\n", level + 1); 310 | for (int j = 0 ; j < classCount; j++) { 311 | int count = details[j].referLevelCount[level]; 312 | if (count) { 313 | out->printf("\t\t%10d %s\n", count, details[j].signature); 314 | details[j].referLevelCount[level] = 0; 315 | } 316 | } 317 | out->printf("\n"); 318 | } 319 | 320 | clearTags(jvmti); 321 | } 322 | 323 | 324 | /* IterateThroughHeap callback that aggregates counts and sizes by class. */ 325 | static jvmtiIterationControl JNICALL heapObject(jlong class_tag, jlong size, jlong* tag_ptr, void* user_data) { 326 | if (class_tag != (jlong)0) { 327 | ClassDetails *d = (ClassDetails*)(void*)(ptrdiff_t)class_tag; 328 | gdata->totalCount++; 329 | d->count++; 330 | d->space += size; 331 | } 332 | return JVMTI_ITERATION_CONTINUE; 333 | } 334 | 335 | 336 | /* Comparison function for two ClassDetails - used to sort largest size first. */ 337 | static int compareDetails(const void *p1, const void *p2) { 338 | return ((ClassDetails*)p2)->space - ((ClassDetails*)p1)->space; 339 | } 340 | 341 | 342 | /* Prints a heap histogram. */ 343 | void JNICALL printHistogram(jvmtiEnv *jvmti, Output *out, bool includeReferrers) { 344 | if (!gdata->vmDeathCalled && !gdata->dumpInProgress) { 345 | jint i; 346 | 347 | gdata->dumpInProgress = JNI_TRUE; 348 | gdata->totalCount = 0; 349 | 350 | AllClassDetails classes(jvmti); 351 | 352 | /* Iterate over the heap and count up uses of jclass */ 353 | CHECK(jvmti->IterateOverHeap(JVMTI_HEAP_OBJECT_EITHER, &heapObject, NULL)); 354 | 355 | /* Remove tags */ 356 | for (i = 0 ; i < classes.count ; i++) { 357 | /* Un-Tag this jclass */ 358 | CHECK(jvmti->SetTag(classes.classes[i], (jlong)0)); 359 | } 360 | 361 | /* Sort details by space used */ 362 | qsort(classes.details, classes.count, sizeof(ClassDetails), &compareDetails); 363 | 364 | /* Print out sorted table */ 365 | out->printf("Heap View, Total of %d objects found.\n\n", gdata->totalCount); 366 | 367 | out->printf("Space Count Retained Class Signature\n"); 368 | out->printf("---------- ---------- ---------- ----------------------\n"); 369 | 370 | for (i = 0 ; i < classes.count ; i++) { 371 | if (classes.details[i].space == 0) { 372 | break; 373 | } 374 | long retainedSize = 0; 375 | for (int j = 0; j < gdata->retainedSizeClassCount; j++) { 376 | if (endswith(classes.details[i].signature, gdata->retainedSizeClasses[j], 1)) { 377 | retainedSize = getRetainedSize(jvmti, classes.details[i].klass); 378 | break; 379 | } 380 | } 381 | out->printf("%10d %10d %10ld %s\n", 382 | classes.details[i].space, classes.details[i].count, retainedSize, classes.details[i].signature); 383 | if (i == 0 && includeReferrers) { 384 | printRefererSummary(jvmti, out, classes.details, classes.count, i); 385 | } 386 | out->flush(); 387 | } 388 | out->printf("---------- ---------- ----------------------\n\n"); 389 | out->flush(); 390 | 391 | gdata->dumpInProgress = JNI_FALSE; 392 | } 393 | } 394 | 395 | 396 | void printClassStats(jvmtiEnv *jvmti, const char *signature, Output *out, bool details) { 397 | if (gdata->vmDeathCalled || gdata->dumpInProgress) { 398 | return; 399 | } 400 | 401 | gdata->dumpInProgress = JNI_TRUE; 402 | 403 | /* Get all the loaded classes */ 404 | AllClassDetails classes(jvmti); 405 | jint offset = classes.getSignatureOffset(signature); 406 | 407 | if (offset == -1) { 408 | out->printf("No class found with signature: '%s'\n", signature); 409 | 410 | } else { 411 | /* Iterate over the heap and count up uses of the desired class */ 412 | CHECK(jvmti->IterateOverHeap(JVMTI_HEAP_OBJECT_EITHER, &heapObject, NULL)); 413 | 414 | ClassDetails d = classes.details[offset]; 415 | out->printf("Count: %d\n", d.count); 416 | out->printf("Space: %d\n", d.space); 417 | if (details) { 418 | out->printf("Retained: %d\n", getRetainedSize(jvmti, d.klass)); 419 | } 420 | 421 | CHECK(jvmti->SetTag(d.klass, (jlong)0)); 422 | } 423 | 424 | gdata->dumpInProgress = JNI_FALSE; 425 | } 426 | 427 | 428 | void printReferrers(jvmtiEnv *jvmti, const char *signature, Output *out) { 429 | if (gdata->vmDeathCalled || gdata->dumpInProgress) { 430 | return; 431 | } 432 | 433 | gdata->dumpInProgress = JNI_TRUE; 434 | 435 | /* Get all the loaded classes */ 436 | AllClassDetails classes(jvmti); 437 | jint offset = classes.getSignatureOffset(signature); 438 | 439 | if (offset == -1) { 440 | out->printf("No class found with signature: '%s'\n", signature); 441 | } else { 442 | printRefererSummary(jvmti, out, classes.details, classes.count, offset); 443 | } 444 | 445 | gdata->dumpInProgress = JNI_FALSE; 446 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Polarbear 2 | ========= 3 | 4 | A tool to help diagnose OutOfMemoryError conditions. 5 | ---------------------------------------------------- 6 | 7 | Polarbear helps track down the root cause of OutOfMemoryError exceptions in Java. When the JVM runs out of memory, 8 | polarbear will log detailed information about what threads are running and what objects are live to /tmp/oom.log for 9 | later review. 10 | 11 | ### Status: 12 | 13 | This is a very early stage project. It works for our needs. We haven't verified it works beyond that. Issue reports 14 | and patches are very much appreciated! 15 | 16 | 17 | ### Installation 18 | 19 | OS X: 20 | 21 | gnumake J2SDK=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home OSNAME=darwin clean test 22 | 23 | 24 | Ubuntu: 25 | 26 | make J2SDK=/usr/lib/jvm/java-1.6.0-openjdk OSNAME=linux clean test 27 | 28 | 29 | Running make will build a JVMTI library. You can enable with a command line flag like the following: 30 | 31 | -agentpath:/path/to/liboutOfMemory.so=ImportantClass,AnotherImportantClass 32 | 33 | This will produce the normal output (see Sample Output below) in addition to calculating retained sizes for ImportantClass 34 | and AnotherImportantClass instances. 35 | 36 | ### polarbear shell 37 | 38 | 39 | polarbear provides a limited repl on 8787 that allows you to interact directly. 40 | 41 | #### Note: 8787 is not secure or fault tolerant and MUST be protected in other ways 42 | 43 | 44 | ``` 45 | > telnet localhost 8787 46 | 47 | histogram 48 | 49 | [...] 50 | 51 | stats Lorg/apache/lucene/index/IndexWriter; 52 | 53 | [...] 54 | ``` 55 | 56 | 57 | 58 | 59 | ### Sample Output 60 | 61 | Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 62 | at java.lang.StringBuilder.toString(StringBuilder.java:430) 63 | at Test.main(Test.java:16) 64 | Initializing polarbear. 65 | 66 | Performing retained size analysis for 2 classes: 67 | HashMap 68 | OOMList 69 | 70 | About to throw an OutOfMemory error. 71 | Suspending all threads except the current one. 72 | Printing a heap histogram. 73 | Heap View, Total of 799172 objects found. 74 | 75 | Space Count Retained Class Signature 76 | ---------- ---------- ---------- ---------------------- 77 | 31692904 396154 0 [C 78 | Collecting references... Finding references to references... Aggregating references... 79 | Level 1 referrers: 80 | 396191 Ljava/lang/String; 81 | 3 Ljava/lang/Thread; 82 | 1 Ljava/lang/ThreadLocal$ThreadLocalMap$Entry; 83 | 1 Ljava/lang/ref/Finalizer$FinalizerThread; 84 | 1 Ljava/lang/ref/Reference$ReferenceHandler; 85 | 2 Ljava/io/BufferedWriter; 86 | 1 Ljava/lang/StringBuilder; 87 | 88 | Level 2 referrers: 89 | 313 [Ljava/lang/Object; 90 | 314 Ljava/util/HashMap$Entry; 91 | 166 Ljava/util/LinkedHashMap$Entry; 92 | 309 Ljava/util/Hashtable$Entry; 93 | 186 Ljava/util/LinkedList$Entry; 94 | 259 Ljava/lang/Integer; 95 | 8 Lsun/security/util/ObjectIdentifier; 96 | 48 Ljava/security/Provider$Service; 97 | 40 Ljava/net/URL; 98 | 59 [Ljava/lang/String; 99 | 93 Ljava/security/Provider$ServiceKey; 100 | 46 Ljava/security/Provider$UString; 101 | 31 Ljava/util/concurrent/ConcurrentHashMap$HashEntry; 102 | 30 Ljava/security/Provider$EngineDescription; 103 | 16 Ljava/util/jar/JarFile; 104 | 23 Lsun/security/x509/OIDMap$OIDInfo; 105 | 28 Ljava/io/ExpiringCache$Entry; 106 | 16 Ljava/io/ObjectStreamField; 107 | 19 Ljava/util/Locale; 108 | 18 Lsun/security/x509/RDN; 109 | 21 Lsun/security/x509/AVAKeyword; 110 | 4 Ljava/lang/reflect/Method; 111 | 17 Ljava/util/jar/Attributes$Name; 112 | 11 Lsun/security/jca/ProviderConfig; 113 | 4 Ljava/util/jar/JarFile$JarFileEntry; 114 | 1 Ljava/lang/ref/WeakReference; 115 | 4 Ljava/lang/OutOfMemoryError; 116 | 1 [Ljava/lang/ThreadLocal$ThreadLocalMap$Entry; 117 | 2 Lsun/security/provider/Sun; 118 | 3 Lsun/security/x509/X500Name; 119 | 7 Lsun/security/x509/NetscapeCertTypeExtension$MapEntry; 120 | 2 Ljava/lang/reflect/Field; 121 | 2 Lsun/nio/cs/MacRoman$Encoder; 122 | 2 Lsun/security/x509/X509CertImpl; 123 | 5 Lsun/security/jca/ServiceId; 124 | 4 Ljava/io/File; 125 | 1 Lsun/security/jca/ProviderList$1; 126 | 2 Ljava/lang/ThreadGroup; 127 | 2 Ljava/util/Properties; 128 | 4 Ljava/text/Normalizer$Form; 129 | 3 Lsun/misc/Signal; 130 | 3 Ljava/lang/RuntimePermission; 131 | 2 Ljava/security/AlgorithmParameters; 132 | 2 Ljava/io/PrintStream; 133 | 2 [Ljava/lang/Thread; 134 | 3 Ljava/nio/charset/CodingErrorAction; 135 | 1 Ljava/io/UnixFileSystem; 136 | 1 Ljava/lang/ArithmeticException; 137 | 1 Ljava/lang/ClassLoader$NativeLibrary; 138 | 1 Ljava/io/FilePermission; 139 | 1 Lsun/nio/cs/StandardCharsets; 140 | 2 Ljava/nio/ByteOrder; 141 | 1 Lcom/apple/java/Usage; 142 | 1 Ljava/lang/reflect/ReflectPermission; 143 | 1 Lsun/nio/cs/US_ASCII; 144 | 1 Lsun/security/provider/certpath/X509CertPath; 145 | 1 Lsun/nio/cs/UTF_8; 146 | 1 Lsun/nio/cs/MacRoman; 147 | 1 Lsun/security/x509/RFC822Name; 148 | 149 | Level 3 referrers: 150 | 10 [Ljava/lang/Object; 151 | 62 [Ljava/util/HashMap$Entry; 152 | 49 Ljava/util/HashMap$Entry; 153 | 96 Ljava/util/LinkedHashMap$Entry; 154 | 6 Ljava/util/Hashtable$Entry; 155 | 102 Ljava/util/LinkedList$Entry; 156 | 13 [Ljava/util/Hashtable$Entry; 157 | 79 Ljava/math/BigInteger; 158 | 2 Ljava/lang/reflect/Constructor; 159 | 21 [Ljava/util/concurrent/ConcurrentHashMap$HashEntry; 160 | 1 [Ljava/lang/Integer; 161 | 17 Ljava/lang/ref/Finalizer; 162 | 2 Ljava/util/Vector; 163 | 23 Lsun/security/util/DerInputBuffer; 164 | 23 Lsun/security/util/DerValue; 165 | 16 Lsun/misc/URLClassPath$JarLoader; 166 | 7 [Ljava/lang/Class; 167 | 23 Ljava/util/ArrayList; 168 | 21 Lsun/security/x509/AVA; 169 | 19 Ljava/lang/Object; 170 | 16 Ljava/lang/Byte; 171 | 5 Ljava/lang/ref/WeakReference; 172 | 6 [Ljava/io/ObjectStreamField; 173 | 9 Lsun/misc/JarIndex; 174 | 6 Lsun/security/x509/AlgorithmId; 175 | 3 [Lsun/security/x509/RDN; 176 | 2 Lsun/security/x509/X509CertInfo; 177 | 2 Lsun/security/util/MemoryCache$SoftCacheEntry; 178 | 2 Lsun/nio/cs/StreamEncoder; 179 | 6 Ljava/util/concurrent/atomic/AtomicInteger; 180 | 4 Ljava/util/Date; 181 | 1 Ljava/util/jar/JarVerifier; 182 | 1 [Lsun/security/jca/ProviderConfig; 183 | 1 Lsun/misc/Launcher$ExtClassLoader; 184 | 2 Lsun/security/x509/AuthorityKeyIdentifierExtension; 185 | 1 Ljava/lang/ThreadLocal$ThreadLocalMap; 186 | 1 Lsun/misc/Launcher$AppClassLoader; 187 | 2 Lsun/misc/URLClassPath; 188 | 2 Lsun/security/x509/NetscapeCertTypeExtension; 189 | 2 Ljava/io/OutputStreamWriter; 190 | 2 Ljava/security/Permissions; 191 | 2 Lsun/security/x509/SubjectKeyIdentifierExtension; 192 | 2 Lsun/security/x509/CertificateValidity; 193 | 1 LTest$OOMList; 194 | 2 Lsun/security/x509/CertificateIssuerName; 195 | 2 Ljava/nio/charset/CoderResult; 196 | 1 [Ljava/io/File; 197 | 2 Lsun/security/provider/DSAParameters; 198 | 1 [Lsun/security/x509/NetscapeCertTypeExtension$MapEntry; 199 | 2 Lsun/security/x509/CertificateExtensions; 200 | 2 Lsun/security/jca/ProviderList; 201 | 2 Lsun/security/x509/CertificateSubjectName; 202 | 1 Ljava/security/ProtectionDomain; 203 | 1 Ljava/io/BufferedInputStream; 204 | 1 Lsun/nio/cs/StandardCharsets$Aliases; 205 | 1 Lsun/nio/cs/StandardCharsets$Cache; 206 | 1 Ljava/util/IdentityHashMap; 207 | 1 [Lsun/security/jca/ServiceId; 208 | 1 Lsun/nio/cs/StandardCharsets$Classes; 209 | 1 Lsun/security/x509/BasicConstraintsExtension; 210 | 1 [Ljava/text/Normalizer$Form; 211 | 1 Lsun/security/x509/KeyUsageExtension; 212 | 2 Lsun/security/x509/CertificateVersion; 213 | 2 Lsun/net/www/protocol/jar/Handler; 214 | 2 Ljava/lang/Boolean; 215 | 1 Ljava/security/CodeSource; 216 | 1 [Ljava/lang/ThreadGroup; 217 | 2 Lsun/security/x509/CertificateSerialNumber; 218 | 1 Ljava/lang/ref/Reference; 219 | 1 Lsun/security/x509/SubjectAlternativeNameExtension; 220 | 2 Lsun/security/x509/CertificateX509Key; 221 | 1 Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl; 222 | 2 Lsun/security/x509/CertificateAlgorithmId; 223 | 1 Ljava/security/BasicPermissionCollection; 224 | 1 Lsun/misc/URLClassPath$FileLoader; 225 | 1 Ljava/math/MutableBigInteger; 226 | 1 Ljava/security/CodeSigner; 227 | 1 Ljava/io/FilePermissionCollection; 228 | 1 Ljava/util/BitSet; 229 | 1 Lsun/misc/Launcher$Factory; 230 | 1 Lsun/net/www/protocol/file/Handler; 231 | 1 Ljava/util/jar/JavaUtilJarAccessImpl; 232 | 1 Lcom/apple/java/Usage$1; 233 | 1 Lsun/reflect/ReflectionFactory; 234 | 1 Lsun/security/x509/GeneralName; 235 | 1 Lsun/misc/Launcher; 236 | 237 | 12678432 396201 0 Ljava/lang/String; 238 | 5823928 356 0 [Ljava/lang/Object; 239 | 464552 660 0 Ljava/lang/Class; 240 | 124248 751 0 [B 241 | 59024 856 0 [S 242 | 39664 788 0 [I 243 | 16432 83 0 [Ljava/util/HashMap$Entry; 244 | 12064 377 0 Ljava/util/HashMap$Entry; 245 | 10720 268 0 Ljava/util/LinkedHashMap$Entry; 246 | 10080 315 0 Ljava/util/Hashtable$Entry; 247 | 6912 288 0 Ljava/util/LinkedList$Entry; 248 | 4144 259 0 Ljava/lang/Integer; 249 | 3600 75 474416 Ljava/util/HashMap; 250 | 3280 17 0 [Ljava/util/Hashtable$Entry; 251 | 3160 79 0 Ljava/math/BigInteger; 252 | 2736 114 0 Lsun/security/util/ObjectIdentifier; 253 | 2688 48 0 Ljava/security/Provider$Service; 254 | 2560 40 0 Ljava/net/URL; 255 | 2488 60 0 [Ljava/lang/String; 256 | 2448 102 0 Ljava/util/LinkedList; 257 | 2232 93 0 Ljava/security/Provider$ServiceKey; 258 | 1920 48 0 Ljava/util/concurrent/ConcurrentHashMap$Segment; 259 | 1584 22 0 Ljava/lang/reflect/Constructor; 260 | 1536 48 0 Ljava/util/concurrent/locks/ReentrantLock$NonfairSync; 261 | 1200 30 0 Ljava/lang/ref/SoftReference; 262 | 1192 48 0 [Ljava/util/concurrent/ConcurrentHashMap$HashEntry; 263 | 1104 46 0 Ljava/security/Provider$UString; 264 | 1040 1 0 [Ljava/lang/Integer; 265 | 1000 25 0 Ljava/lang/ref/Finalizer; 266 | 992 31 0 Ljava/util/concurrent/ConcurrentHashMap$HashEntry; 267 | 960 30 0 Ljava/security/Provider$EngineDescription; 268 | 896 16 0 Ljava/util/jar/JarFile; 269 | 784 7 0 Ljava/lang/Thread; 270 | 736 23 0 Ljava/util/Vector; 271 | 736 23 0 Lsun/security/util/DerInputBuffer; 272 | 736 23 0 Lsun/security/util/DerValue; 273 | 736 23 0 Lsun/security/x509/OIDMap$OIDInfo; 274 | 672 28 0 Ljava/io/ExpiringCache$Entry; 275 | 640 16 0 Lsun/misc/URLClassPath$JarLoader; 276 | 640 16 0 Ljava/io/ObjectStreamField; 277 | 608 19 0 Ljava/util/Locale; 278 | 592 3 0 [J 279 | 576 25 0 [Ljava/lang/Class; 280 | 576 12 0 Ljava/util/Hashtable; 281 | 552 23 0 Lsun/security/util/DerInputStream; 282 | 552 23 0 Ljava/util/ArrayList; 283 | 504 21 0 Lsun/security/x509/RDN; 284 | 504 21 0 Lsun/security/x509/AVAKeyword; 285 | 504 21 0 [Lsun/security/x509/AVA; 286 | 504 21 0 Lsun/security/x509/AVA; 287 | 440 5 0 Ljava/lang/reflect/Method; 288 | 408 17 0 Ljava/util/jar/Attributes$Name; 289 | 368 23 0 Ljava/lang/Object; 290 | 352 11 0 Lsun/security/jca/ProviderConfig; 291 | 352 11 0 Ljava/security/AccessControlContext; 292 | 344 3 0 [Ljava/math/BigInteger; 293 | 336 6 208576 Ljava/util/LinkedHashMap; 294 | 336 14 0 [Ljava/lang/Byte; 295 | 320 4 0 Ljava/util/jar/JarFile$JarFileEntry; 296 | 312 3 0 [D 297 | 256 16 0 Ljava/lang/Byte; 298 | 256 8 0 Ljava/lang/ref/WeakReference; 299 | 256 8 0 Ljava/lang/OutOfMemoryError; 300 | 240 3 0 [Ljava/lang/ThreadLocal$ThreadLocalMap$Entry; 301 | 240 3 0 [Ljava/util/concurrent/ConcurrentHashMap$Segment; 302 | 240 10 0 Lsun/reflect/NativeConstructorAccessorImpl; 303 | 224 9 0 [Ljava/io/ObjectStreamField; 304 | 216 9 0 Lsun/misc/JarIndex; 305 | 192 2 0 Lsun/security/provider/Sun; 306 | 192 4 0 Lsun/security/x509/X500Name; 307 | 192 6 0 Lsun/security/x509/AlgorithmId; 308 | 168 7 0 Lsun/security/x509/NetscapeCertTypeExtension$MapEntry; 309 | 160 10 0 Lsun/reflect/DelegatingConstructorAccessorImpl; 310 | 152 4 0 [Lsun/security/x509/RDN; 311 | 144 2 0 Ljava/lang/reflect/Field; 312 | 144 2 0 Lsun/nio/cs/MacRoman$Encoder; 313 | 144 2 0 Lsun/security/x509/X509CertImpl; 314 | 144 3 751160 Ljava/util/concurrent/ConcurrentHashMap; 315 | 128 4 0 Ljava/lang/ThreadLocal$ThreadLocalMap$Entry; 316 | 128 4 0 Ljava/lang/ref/ReferenceQueue; 317 | 120 5 0 Lsun/security/jca/ServiceId; 318 | 120 5 0 Ljava/io/FileDescriptor; 319 | 112 2 0 Lsun/security/x509/X509CertInfo; 320 | 112 1 0 Ljava/lang/ref/Finalizer$FinalizerThread; 321 | 112 1 0 Ljava/lang/ref/Reference$ReferenceHandler; 322 | 112 2 0 Lsun/security/util/MemoryCache$SoftCacheEntry; 323 | 112 2 0 Lsun/nio/cs/StreamEncoder; 324 | 112 2 0 Ljava/io/ExpiringCache$1; 325 | 112 4 0 [Z 326 | 96 3 0 Ljava/util/zip/Inflater; 327 | 96 2 0 Ljava/nio/HeapByteBuffer; 328 | 96 6 0 Ljava/lang/ref/ReferenceQueue$Lock; 329 | 96 3 0 Ljava/io/FileInputStream; 330 | 96 4 0 Ljava/io/File; 331 | 96 1 0 Lsun/security/jca/ProviderList$1; 332 | 96 2 0 Ljava/lang/ThreadGroup; 333 | 96 2 0 Ljava/io/BufferedWriter; 334 | 96 6 0 Ljava/util/concurrent/atomic/AtomicInteger; 335 | 96 3 0 Ljava/util/Stack; 336 | 96 4 0 Ljava/util/Date; 337 | 96 2 0 Ljava/util/Properties; 338 | 96 4 0 Ljava/text/Normalizer$Form; 339 | 88 1 0 [[Ljava/lang/Byte; 340 | 88 1 0 [Lsun/security/util/ObjectIdentifier; 341 | 88 1 0 Ljava/util/jar/JarVerifier; 342 | 80 1 0 [[B 343 | 80 2 0 Lsun/security/provider/DSAPublicKeyImpl; 344 | 80 2 0 Ljava/io/ExpiringCache; 345 | 80 2 0 [Lsun/security/jca/ProviderConfig; 346 | 80 1 0 Lsun/misc/Launcher$ExtClassLoader; 347 | 80 5 0 Ljava/lang/ThreadLocal; 348 | 80 2 0 Lsun/security/x509/AuthorityKeyIdentifierExtension; 349 | 72 3 0 Ljava/lang/ThreadLocal$ThreadLocalMap; 350 | 72 3 0 Lsun/misc/Signal; 351 | 72 3 0 Ljava/util/zip/ZStreamRef; 352 | 72 3 0 Ljava/lang/RuntimePermission; 353 | 72 1 0 Lsun/misc/Launcher$AppClassLoader; 354 | 64 1 0 [F 355 | 64 2 0 Lsun/misc/URLClassPath; 356 | 64 2 0 Ljava/security/AlgorithmParameters; 357 | 64 1 0 Lsun/security/provider/NativePRNG$RandomIO; 358 | 64 2 0 Lsun/security/x509/NetscapeCertTypeExtension; 359 | 64 2 0 Ljava/io/OutputStreamWriter; 360 | 64 4 0 Lsun/security/x509/KeyIdentifier; 361 | 64 2 0 Lsun/security/util/MemoryCache; 362 | 64 4 0 Ljava/util/HashMap$EntrySet; 363 | 64 2 0 Ljava/io/PrintStream; 364 | 64 2 0 Ljava/lang/ref/ReferenceQueue$Null; 365 | 64 2 0 Ljava/io/FileOutputStream; 366 | 64 2 0 Ljava/security/Permissions; 367 | 64 2 0 [Ljava/lang/Thread; 368 | 64 2 0 Lsun/security/x509/SubjectKeyIdentifierExtension; 369 | 56 1 0 [Ljava/lang/Runnable; 370 | 48 2 0 Lsun/security/x509/CertificateValidity; 371 | 48 2 50776680 LTest$OOMList; 372 | 48 2 0 Lsun/security/x509/CertificateIssuerName; 373 | 48 2 0 Ljava/nio/charset/CoderResult; 374 | 48 3 0 Lsun/text/normalizer/NormalizerBase$QuickCheckResult; 375 | 48 2 0 Lsun/misc/NativeSignalHandler; 376 | 48 2 0 [Ljava/io/File; 377 | 48 2 0 Lsun/security/provider/DSAParameters; 378 | 48 2 0 Ljava/io/BufferedOutputStream; 379 | 48 1 0 [Lsun/security/x509/NetscapeCertTypeExtension$MapEntry; 380 | 48 2 0 Lsun/security/x509/CertificateExtensions; 381 | 48 2 0 Lsun/security/util/BitArray; 382 | 48 2 0 Lsun/security/jca/ProviderList; 383 | 48 2 0 Lsun/security/x509/CertificateSubjectName; 384 | 48 2 0 Lsun/nio/cs/Surrogate$Parser; 385 | 48 3 0 Ljava/nio/charset/CodingErrorAction; 386 | 48 2 0 Lsun/security/jca/ProviderList$3; 387 | 48 2 0 Lsun/security/util/Cache$EqualByteArray; 388 | 40 1 0 Ljava/security/ProtectionDomain; 389 | 40 2 0 [Ljava/security/CodeSigner; 390 | 40 1 0 Ljava/io/BufferedInputStream; 391 | 40 1 0 Lsun/nio/cs/StandardCharsets$Aliases; 392 | 40 1 0 Lsun/nio/cs/StandardCharsets$Cache; 393 | 40 1 27544 Ljava/util/IdentityHashMap; 394 | 40 1 0 [Lsun/security/jca/ServiceId; 395 | 40 1 0 Lsun/nio/cs/StandardCharsets$Classes; 396 | 32 1 0 Ljava/lang/VirtualMachineError; 397 | 32 1 0 Ljava/util/Collections$SynchronizedMap; 398 | 32 1 0 [Ljava/lang/OutOfMemoryError; 399 | 32 1 0 Lsun/security/x509/BasicConstraintsExtension; 400 | 32 1 0 [Ljava/text/Normalizer$Form; 401 | 32 2 0 Lsun/security/x509/SerialNumber; 402 | 32 1 0 Ljava/lang/NullPointerException; 403 | 32 1 0 Lsun/security/x509/KeyUsageExtension; 404 | 32 1 0 Lsun/misc/SoftCache; 405 | 32 2 0 Lsun/security/x509/CertificateVersion; 406 | 32 2 0 Lsun/net/www/protocol/jar/Handler; 407 | 32 2 0 Ljava/lang/Boolean; 408 | 32 2 0 Ljava/lang/Shutdown$Lock; 409 | 32 1 0 Ljava/security/CodeSource; 410 | 32 1 0 [Ljava/lang/ThreadGroup; 411 | 32 2 0 Lsun/security/x509/CertificateSerialNumber; 412 | 32 1 0 Ljava/lang/ref/Reference; 413 | 32 1 0 Ljava/io/UnixFileSystem; 414 | 32 1 0 Lsun/security/x509/SubjectAlternativeNameExtension; 415 | 32 1 0 Ljava/lang/ArithmeticException; 416 | 32 1 0 Ljava/lang/ClassLoader$NativeLibrary; 417 | 32 1 0 Ljava/io/FilePermission; 418 | 32 2 0 Lsun/security/x509/CertificateX509Key; 419 | 32 2 0 Ljava/util/HashSet; 420 | 32 1 0 Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl; 421 | 32 1 0 Lsun/nio/cs/StandardCharsets; 422 | 32 2 0 Lsun/security/x509/CertificateAlgorithmId; 423 | 32 2 0 Ljava/nio/ByteOrder; 424 | 32 1 0 Ljava/security/BasicPermissionCollection; 425 | 24 1 0 Lcom/apple/java/Usage; 426 | 24 1 0 Ljava/lang/reflect/ReflectPermission; 427 | 24 1 0 Lsun/misc/URLClassPath$FileLoader; 428 | 24 1 0 Ljava/util/Collections$UnmodifiableRandomAccessList; 429 | 24 1 0 Lsun/nio/cs/US_ASCII; 430 | 24 1 0 Ljava/math/MutableBigInteger; 431 | 24 1 0 Ljava/util/Collections$EmptyMap; 432 | 24 1 0 Lsun/security/provider/certpath/X509CertPath; 433 | 24 1 0 Ljava/security/Policy$UnsupportedEmptyCollection; 434 | 24 1 0 Ljava/security/CodeSigner; 435 | 24 1 0 Lsun/nio/cs/UTF_8; 436 | 24 1 0 Ljava/io/FilePermissionCollection; 437 | 24 1 0 Ljava/lang/StringBuilder; 438 | 24 1 0 Ljava/util/Arrays$ArrayList; 439 | 24 1 0 Lsun/nio/cs/MacRoman; 440 | 24 1 0 Ljava/util/BitSet; 441 | 16 1 0 [Ljava/security/Provider; 442 | 16 1 0 Lsun/jkernel/DownloadManager$1; 443 | 16 1 0 Lsun/text/normalizer/NormalizerBase$NFKCMode; 444 | 16 1 0 Lsun/misc/Launcher$Factory; 445 | 16 1 0 Ljava/nio/charset/CoderResult$2; 446 | 16 1 0 Lsun/net/www/protocol/file/Handler; 447 | 16 1 0 Ljava/util/jar/JavaUtilJarAccessImpl; 448 | 16 1 0 Ljava/lang/System$2; 449 | 16 1 0 Ljava/lang/reflect/ReflectAccess; 450 | 16 1 0 Lsun/misc/FloatingDecimal$1; 451 | 16 1 0 Ljava/util/jar/JarVerifier$3; 452 | 16 1 0 Lsun/text/normalizer/NormalizerBase$Mode; 453 | 16 1 0 Ljava/util/Collections$EmptySet; 454 | 16 1 0 Ljava/util/Hashtable$EmptyEnumerator; 455 | 16 1 0 Lsun/misc/ASCIICaseInsensitiveComparator; 456 | 16 1 0 [Ljava/security/cert/Certificate; 457 | 16 1 0 Ljava/security/ProtectionDomain$Key; 458 | 16 1 0 Lcom/apple/java/Usage$1; 459 | 16 1 0 Ljava/lang/Runtime; 460 | 16 1 0 Ljava/security/AccessControlContext$1; 461 | 16 1 0 [Ljava/lang/StackTraceElement; 462 | 16 1 0 Lsun/text/normalizer/NormalizerBase$NFDMode; 463 | 16 1 0 Ljava/util/Collections$UnmodifiableCollection; 464 | 16 1 0 Ljava/util/Collections$EmptyList; 465 | 16 1 0 Ljava/lang/InheritableThreadLocal; 466 | 16 1 0 Ljava/nio/charset/CoderResult$1; 467 | 16 1 0 Lsun/security/x509/RFC822Name; 468 | 16 1 0 Lsun/reflect/ReflectionFactory; 469 | 16 1 0 Ljava/lang/Terminator$1; 470 | 16 1 0 Ljava/lang/ApplicationShutdownHooks$1; 471 | 16 1 0 Lsun/security/util/ByteArrayLexOrder; 472 | 16 1 0 Ljava/net/URLClassLoader$7; 473 | 16 1 0 [Ljava/security/Principal; 474 | 16 1 0 Lsun/security/util/ByteArrayTagOrder; 475 | 16 1 0 Lsun/security/x509/GeneralName; 476 | 16 1 0 Ljava/util/regex/Pattern$5; 477 | 16 1 0 Ljava/lang/String$CaseInsensitiveComparator; 478 | 16 1 0 Lsun/util/calendar/Gregorian; 479 | 16 1 0 Lsun/security/x509/GeneralNames; 480 | 16 1 0 Lsun/misc/Launcher; 481 | 16 1 0 Ljava/util/regex/Pattern$Node; 482 | 16 1 0 Ljava/lang/ref/Reference$Lock; 483 | 16 1 0 Lsun/text/normalizer/NormalizerBase$NFCMode; 484 | 16 1 0 Ljava/util/Collections$ReverseComparator; 485 | 16 1 0 Lsun/misc/Unsafe; 486 | 16 1 0 Lsun/text/normalizer/NormalizerBase$NFKDMode; 487 | 16 1 0 Ljava/util/Hashtable$EmptyIterator; 488 | 16 1 0 Ljava/security/ProtectionDomain$2; 489 | 16 1 0 Ljava/net/UnknownContentHandler; 490 | 16 1 0 Ljava/io/FileDescriptor$1; 491 | 16 1 0 Ljava/util/regex/Pattern$LastNode; 492 | ---------- ---------- ---------------------- 493 | 494 | Resuming threads. 495 | Printing thread dump. 496 | 497 | Dumping thread state for 4 threads 498 | 499 | #1 - Signal Dispatcher - RUNNABLE 500 | 501 | #2 - Finalizer - WAITING 502 | at java.lang.Object.wait(Object.java) 503 | at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) 504 | at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134) 505 | at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159) 506 | 507 | #3 - Reference Handler - WAITING 508 | at java.lang.Object.wait(Object.java) 509 | at java.lang.Object.wait(Object.java:485) 510 | at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116) 511 | 512 | #4 - main - RUNNABLE - [OOM thrower] 513 | at java.lang.StringBuilder.toString(StringBuilder.java:430) 514 | at Test.main(Test.java:16) 515 | 516 | 517 | ### License 518 | 519 | Polarbear is based on Sun Microsystems sample JVMTI code, and follows the license rules issued by Sun. 520 | All modifications are released under the same license. 521 | 522 | 523 | ### Polarbear? 524 | 525 | If you were a fan of LOST, you may understand why "Out of memory" and polar bears are related thoughts for us. 526 | --------------------------------------------------------------------------------