Java 内存泄露 Memory Leak(Oracle官方文档)

关于Java中是否存在内存泄露的问题,很多人都争执不休,但是Java的官方Oracle给出了说明,所以这个问题可以休了,即JAVA确实存在内存泄露,并给出定义:虚拟内存被分配了但该内存不在需要时,却没有被回收。

内存泄露的表现是抛出OutofMemoryError,但是出现OutofMemoryError却并不代表一定内存泄露,有可能是因为JVM的配置参数不合适导致的,但是经过长时间运行才抛出改异常,是内存泄露的可能就非常大了。


首先看一个对象的消亡示例,对象离开作用域就不在有用,下面的这个例子很好的解释了关于对象与作用域的关系

public class Test {
    public static void main(String[] args) {
        B b = null;
        {
            A a = new A();
            b = a.getB();
        } //离开这个花括号,a消亡,a的属性b也不复存在(注意b是变量),但是main的b还是存在
          //main的b指向a的b所指向的对象,所以在A的构造方法中new出来的b对象依然没有消亡
          //a对象有自己的内存空间,b对象有自己的内存空间
          //a的b属性只是一个指针,它指向b对象,即a的b属性的变量本身的内存保存b对象的地址
          //所以a消亡只是a的b指针变量不复存在,并不是b对象不存在,只要还有其他变量引用b的话

        System.out.println(b);
    }
}

class A {
    B b;
    public A() {
        b = new B();
    }

    public B getB() {return B;}
}

class B {

}

Chapter 3

Troubleshooting Memory Leaks

If your application's execution time becomes longer and longer, or if the operating system seems to be performing slower and slower, this could be an indication of a memory leak. In other words, virtual memory is being allocated but is not being returned when it is no longer needed. Eventually the application or the system runs out of memory, and the application terminates abnormally.

This chapter provides some suggestions on diagnosing problems involving possible memory leaks.

3.1 Meaning of OutOfMemoryError

One common indication of a memory leak is the java.lang.OutOfMemoryError error. This error is thrown when there is insufficient space to allocate an object in the Java heap or in a particular area of the heap. The garbage collector cannot make any further space available to accommodate a new object, and the heap cannot be expanded further.

基本的OutofMemeroyError异常来自Heap,持久代(PermGen),栈,本地栈

When the java.lang.OutOfMemoryError error is thrown, a stack trace is printed also.

java.lang.OutOfMemoryError can also be thrown by native library code when a native allocation cannot be satisfied, for example, if swap space is low.

An early step to diagnose an OutOfMemoryError is to determine what the error means. Does it mean that the Java heap is full, or does it mean that the native heap is full? To help you answer this question, the following subsections explain some of the possible error messages, with reference to the detail part of the message:

3.1.1 Detail Message: Java heap space

(短期出现此异常,可能是配置的原因)The detail message Java heap space indicates that an object could not be allocated in the Java heap. This error does not necessarily imply a memory leak. The problem can be as simple as a configuration issue, where the specified heap size (or the default size, if not specified) is insufficient for the application.

(长时间运行导致的异常,为内存泄露)In other cases, and in particular for a long-lived application, the message might be an indication that the application is unintentionally holding references to objects, and this prevents the objects from being garbage collected. This is the Java language equivalent of amemory leak. Note that APIs that are called by an application could also be unintentionally holding object references.

这个地方有明显的实例就好了!!

(过度使用Finalizer导致此异常)One other potential source of OutOfMemoryError arises with applications that make excessive use of finalizers. If a class has a finalize method, then objects of that type do not have their space reclaimed at garbage collection time. Instead, after garbage collection the objects are queued for finalization, which occurs at a later time. In the Sun implementation, finalizers are executed by a daemon thread that services the finalization queue. If the finalizer thread cannot keep up with the finalization queue, then the Java heap could fill up and OutOfMemoryError would be thrown. One scenario that can cause this situation is when an application creates high-priority threads that cause the finalization queue to increase at a rate that is faster than the rate at which the finalizer thread is servicing that queue. Section   3.3.6 Monitoring the Number of Objects Pending Finalization discusses how to monitor objects for which finalization is pending.

3.1.2 Detail Message: PermGen space

(持久代(此处也可成为方法区,因为持久代是hotpot上的概念,从位置上从属于方法区)会抛出异常当需要加载非常多的类时,可以通过调整JVM配置参数避免此异常)The detail message PermGen space indicates that the permanent generation is full. The permanent generation is the area of the heap where class and method objects are stored. If an application loads a very large number of classes, then the size of the permanent generation might need to be increased using the -XX:MaxPermSize option.

(大量使用String.intern()方法会导致此异常,因为intern返回的对Literal字符串的引用)Interned java.lang.String objects are also stored in the permanent generation. Thejava.lang.String class maintains a pool of strings. When the intern method is invoked, the method checks the pool to see if an equal string is already in the pool. If there is, then the internmethod returns it; otherwise it adds the string to the pool. In more precise terms, thejava.lang.String.intern method is used to obtain the canonical representation of the string; the result is a reference to the same class instance that would be returned if that string appeared as a literal. If an application interns a huge number of strings, the permanent generation might need to be increased from its default setting.

关于 String. intern()方法: 关于此方法的用法关乎于对String常量池的的理解,JVM深入浅出,部分关于常量池的解释,简而言之,intern方法可以将String添加常量池,当然如果有常量池中已经存在就不需要添加了,常量池中会保证所以字符串的唯一性。

Returns a canonical representation for the string object. (返回String对象的标准表示形式)

A pool of strings, initially empty, is maintained privately by the class String.

When the intern method is invoked, if the pool already contains a string equal to thisString object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, thisString object is added to the pool and a reference to this String object is returned.

It follows that for any two strings s and t, s.intern() == t.intern() istrue if and only if s.equals(t) is true.

All literal strings and string-valued constant expressions are interned. String literals are defined in §3.10.5 of theJava Language Specification When this kind of error occurs, the text String.intern or ClassLoader.defineClass might appear near the top of the stack trace that is printed.

The jmap -permgen command prints statistics for the objects in the permanent generation, including information about internalized String instances. See   2.7.4 Getting Information on the Permanent Generation.

3.1.3 Detail Message: Requested array size exceeds VM limit

The detail message Requested array size exceeds VM limit indicates that the application (or APIs used by that application) attempted toallocate an array that is larger than the heap size. For example, if an application attempts to allocate an array of 512MB but the maximum heap size is 256MB then OutOfMemoryError will be thrown with the reason Requested array size exceeds VM limit. In most cases the problem is either a configuration issue (heap size too small), or a bug that results in an application attempting to create a huge array, for example, when the number of elements in the array are computed using an algorithm that computes an incorrect size.

3.1.4 Detail Message: request <size> bytes for <reason>. Out of swap space?

The detail message request <size> bytes for <reason>. Out of swap space? appears to be an OutOfMemoryError. However, the HotSpot VM code reports this apparent exception when an allocation from the native heap failed and the native heap might be close to exhaustion. The message indicates the size (in bytes) of the request that failed and the reason for the memory request. In most cases the <reason> part of the message is the name of a source module reporting the allocation failure, although in some cases it indicates a reason.

When this error message is thrown, the VM invokes the fatal error handling mechanism, that is, it generates a fatal error log file, which contains useful information about the thread, process, and system at the time of the crash. In the case of native heap exhaustion, the heap memory and memory map information in the log can be useful. See   Appendix C, Fatal Error Log for detailed information about this file.

If this type of OutOfMemoryError is thrown, you might need to use troubleshooting utilities on the operating system to diagnose the issue further. See   2.16 Operating-System-Specific Tools.

The problem might not be related to the application, for example:

The operating system is configured with insufficient swap space.
Another process on the system is consuming all memory resources.

If neither of the above issues is the cause, then it is possible that the application failed due to a native leak, for example, if application or library code is continuously allocating memory but is not releasing it to the operating system.

3.1.5 Detail Message: <reason> <stack trace> (Native method)

If the detail part of the error message is <reason> <stack trace> (Native method) and a stack trace is printed in which the top frame is a native method, then this is an indication that a native method has encountered an allocation failure. The difference between this and the previous message is that the allocation failure was detected in a JNI or native method rather than in Java VM code.

If this type of OutOfMemoryError is thrown, you might need to use utilities on the operating system to further diagnose the issue. See   2.16 Operating-System-Specific Tools.

3.2 Crash Instead of OutOfMemoryError

Sometimes an application crashes soon after an allocation from the native heap fails. This occurs with native code that does not check for errors returned by memory allocation functions.

For example, the malloc system call returns NULL if there is no memory available. If the return from malloc is not checked, then the application might crash when it attempts to access an invalid memory location. Depending on the circumstances, this type of issue can be difficult to locate.

However, in some cases the information from the fatal error log or the crash dump might be sufficient to diagnose this issue. The fatal error log is covered in detail in   Appendix C, Fatal Error Log. If the cause of a crash is determined to be the failure to check an allocation failure, then the reason for the allocation failure must be examined. As with any other native heap issue, the system might be configured with insufficient swap space, another process on the system might be consuming all memory resources, or there might be a leak in the application (or in the APIs that it calls) that causes the system to run out of memory.

3.3 Diagnosing Leaks in Java Language Code

Diagnosing leaks in Java language code can be a difficult task. In most cases it requires very detailed knowledge of the application. In addition the process is often iterative and lengthy. This section provides the following subsections:

   3.3.1 NetBeans Profiler
   3.3.2 Using the jhat Utility
   3.3.3 Creating a Heap Dump
   3.3.4 Obtaining a Heap Histogram on a Running Process
   3.3.5 Obtaining a Heap Histogram at OutOfMemoryError
   3.3.6 Monitoring the Number of Objects Pending Finalization
   3.3.7 Third Party Memory Debuggers
3.3.1 NetBeans Profiler

The NetBeans Profiler (previously known as JFluid) is an excellent profiler, which can locate memory leaks very quickly. Most commercial memory leak debugging tools can often take a long time to locate a leak in a large application.The NetBeans Profiler, however, uses the pattern of memory allocations and reclamations that such objects typically demonstrate. This process includes also the lack of memory reclamations. The profiler can check where these objects were allocated, which in many cases is sufficient to identify the root cause of the leak.

More details can be found at http://profiler.netbeans.org.

3.3.2 Using the jhat Utility

The jhat utility (see   2.5 jhat Utility ) is useful when debugging unintentional object retention (or memory leaks). It provides a way to browse an object dump(垃圾场), view all reachable objects in the heap, and understand which references are keeping an object alive.

To use jhat you must obtain one or more heap dumps of the running application, and the dumps must be in binary format. Once the dump file is created, it can be used as input to jhat, as described in   2.5 jhat Utility .

3.3.3 Creating a Heap Dump

A heap dump provides detailed information on the allocation of heap memory. The following sections describe several ways to produce a heap dump:

   3.3.3.1 HPROF Profiler
   3.3.3.2 jmap Utility
   3.3.3.3 JConsole Utility
   3.3.3.4 -XX:+HeapDumpOnOutOfMemoryError Command-line Option
3.3.3.1 HPROF Profiler

The HPROF profiler agent can create a heap dump while the application is executing. The following is an example of the command line:

$  
         java -agentlib:hprof=file=snapshot.hprof,format=b  
         application
      

If the VM is embedded or is not started using a command line launcher that allows additional options to be provided, then it might be possible to use the JAVA_TOOLS_OPTIONS environment variable so that the -agentlib option is automatically added to the command line. See   A.2JAVA_TOOL_OPTIONS Environment Variable for further information on this environment variable.

Once the application is running with HPROF, a heap dump is created by pressing Ctrl-\ or Ctrl-Break (depending on the platform) on the application console. An alternative approach on Solaris OS and Linux is to send a QUIT signal with the kill -QUIT pid command. When the signal is received, a heap dump is created; in the above example the file snapshot.hprof is created.

The heap dump file contains all the primitive data and stack traces.

A dump file can contain multiple heap dumps. If Ctrl-\ or Ctrl-Break is pressed a number of times then the subsequent dumps are appended to the file. The jhat utility uses the # n syntax to distinguish the dumps, where n is the dump number.

3.3.3.2 jmap Utility

A heap dump can also be obtained using the jmap utility (see   2.7 jmap Utility ). The following is an example of the command line:

$  
         jmap -dump:format=b,file=snapshot.jmap  
         process-pid
      

Regardless of how the Java VM was started, the jmap tool will produce a head dump snapshot, in the above example in a file called snapshot.jmap. The jmap output files should contain all the primitive data, but will not include any stack traces showing where the objects have been created.

3.3.3.3 JConsole Utility

Another way to obtain a heap dump is with the JConsole utility. In the MBeans tab, select theHotSpotDiagnostic MBean, then the Operations display, and choose the dumpHeap operation.

3.3.3.4 -XX:+HeapDumpOnOutOfMemoryError Command-line Option

If you specify the -XX:+HeapDumpOnOutOfMemoryError command-line option, and if anOutOfMemoryError is thrown, the VM generates a heap dump.

3.3.4 Obtaining a Heap Histogram on a Running Process

You can try to quickly narrow down a memory leak by examining a heap histogram. This information can be obtained in several ways:

A heap histogram can be obtained from a running process using the command  jmap -histo pid . The output shows the total size and instance count for each class type in the heap. If a sequence of histograms is obtained (for example, every 2 minutes), then you might be able to observe a trend that can lead to further analysis.
On Solaris OS and Linux, the  jmap  utility can also provide a histogram from a core file.
If the Java process is started with the  -XX:+PrintClassHistogram  command-line option, then the Ctrl-Break handler will produce a heap histogram.
3.3.5 Obtaining a Heap Histogram at OutOfMemoryError

If you specify the -XX:+HeapDumpOnOutOfMemoryError command-line option, and if anOutOfMemoryError is thrown, the VM generates a heap dump. You can then use the jmap utility to obtain a histogram from the heap dump.

If a core file is produced when the OutOfMemoryError is thrown, you can execute jmap on the core file to get a histogram, as in the following example.

$  
         jmap -histo \ /java/re/javase/6/latest/binaries/solaris-sparc/bin/java core.27421

Attaching to core core.27421 from executable 
/java/re/javase/6/latest/binaries/solaris-sparc/bin/java, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 1.6.0-beta-b63
Iterating over heap. This may take a while...
Heap traversal took 8.902 seconds.

Object Histogram:
 
Size      Count   Class description
-------------------------------------------------------
86683872  3611828 java.lang.String
20979136  204     java.lang.Object[]
403728    4225    * ConstMethodKlass
306608    4225    * MethodKlass
220032    6094    * SymbolKlass
152960    294     * ConstantPoolKlass
108512    277     * ConstantPoolCacheKlass
104928    294     * InstanceKlassKlass
68024     362     byte[]
65600     559     char[]
31592     359     java.lang.Class
27176     462     java.lang.Object[]
25384     423     short[]
17192     307     int[]
:
      

The example shows that the OutOfMemoryError is caused by the number of java.lang.Stringobjects (3611828 instances in the heap). Without further analysis it is not clear where the strings are allocated. However, the information is still useful and the investigation can continue with tools such as HPROF or jhat to find out where the strings are allocated, as well as what references are keeping them alive and preventing them from being garbage collected.

3.3.6 Monitoring the Number of Objects Pending Finalization

As noted in   3.1.1 Detail Message: Java heap space , excessive use of finalizers can be the cause of OutOfMemoryError. You have several options for monitoring the number of objects that are pending finalization.

The JConsole management tool (see     2.3 JConsole Utility ) can be used to monitor the number of objects that are pending finalization. This tool reports the pending finalization count in the memory statistics on the “Summary” tab pane. The count is approximate but it can be used to characterize an application and understand if it relies a lot on finalization.
On Solaris OS and Linux, the  jmap -finalizerinfo  option prints information on objects awaiting finalization.
An application can report the approximate number of objects pending finalization using the getObjectPendingFinalizationCount  method in the java.lang.management.MemoryMXBean  class. Links to the API documentation and example code can be found in     2.17 Developing Diagnostic Tools . The example code can easily be extended to include the reporting of the pending finalization count.
3.3.7 Third Party Memory Debuggers

In addition to the tools mentioned in the previous chapters, there are a large number of third-party memory debuggers available. JProbe from Quest Software, and OptimizeIt from Borland are two examples of commercial tools with memory debugging capability. There are many others and no specific product is recommended.

3.4 Diagnosing Leaks in Native Code

Several techniques can be used to find and isolate native code memory leaks. In general there is no single ideal solution for all platforms.

3.4.1 Tracking All Memory Allocation and Free Calls

A very common practice is to track all allocation and free calls of the native allocations. This can be a fairly simple process or a very sophisticated one. Many products over the years have been built up around the tracking of native heap allocations and the use of that memory.

Tools like Purify and Sun's dbx Run Time Checking (see   3.4.4 Using dbx to Find Leaks ) functionality can be used to find these leaks in normal native code situations and also find any access to native heap memory that represents assignments to uninitialized memory or accesses to freed memory.

Not all these types of tools will work with Java applications that use native code, and usually these tools are platform-specific. Since the virtual machine dynamically creates code at runtime, these tools can wrongly interpret the code and fail to run at all, or give false information. Check with your tool vendor to make sure the version of the tool works with the version of the virtual machine you are using.

Many simple and portable native memory leak detecting examples can be found athttp://sourceforge.net/. Most of these libraries and tools assume that you can recompile or edit the source of the application and place wrapper functions over the allocation functions. The more powerful of these tools allow you to run your application unchanged by interposing over these allocation functions dynamically. This is the case with the library libumem.so, starting with Solaris 9 OS update 3; see   3.4.5 Using libumem to Find Leaks .

3.4.2 Tracking Memory Allocation in a JNI Library

If you write a JNI library, it would probably be wise to create some kind of localized way to make sure your library does not leak memory, using a simple wrapper approach.

The following procedure is an easy localized allocation tracking approach for a JNI library. First, define the following lines in all source files:

#include <stdlib.h>
#define malloc(n) debug_malloc(n, __FILE__, __LINE__)
#define free(p) debug_free(p, __FILE__, __LINE__)

Then you can use the following functions to watch for leaks.

/* Total bytes allocated */
static int total_allocated;
/* Memory alignment is important */
typedef union { double d; struct {size_t n; char *file; int line;} s; } Site;
void *
debug_malloc(size_t n, char *file, int line) 
{ 
    char *rp;
    rp = (char*)malloc(sizeof(Site)+n); 
    total_allocated += n; 
    ((Site*)rp)->s.n = n;
    ((Site*)rp)->s.file = file;
    ((Site*)rp)->s.line = line;
    return (void*)(rp + sizeof(Site));
}
void 
debug_free(void *p, char *file, int line)
{
    char *rp;
    rp = ((char*)p) - sizeof(Site);
    total_allocated -= ((Site*)rp)->s.n;
    free(rp);
}

The JNI library would then need to periodically (or at shutdown) check the value of thetotal_allocated variable to make sure that it made sense. The above code could also be expanded to save in a linked list the allocations that remained and report where the leaked memory was allocated. This is a localized and portable way to track memory allocations in a single set of sources. You would need to make sure that debug_free() was called only with a pointer that came from debug_malloc(), and you would also need to create similar functions forrealloc()calloc()strdup(), and so forth, if they were used.

A more global way to look for native heap memory leaks would involve interposition of the library calls for the entire process.

3.4.3 Tracking Memory Allocation With OS Support

Most operating systems include some form of global allocation tracking support.

On Windows, go to  http://msdn.microsoft.com/library/default.asp  and search for debug support. The Microsoft C++ compiler has the  /Md  and  /Mdd  compiler options that will automatically include extra support for tracking memory allocations.
Linux systems have tools such as  mtrace  and  libnjamd  to help in dealing with allocation tracking.
Solaris Operating Systems provide the  watchmalloc  tool. Solaris 9 OS update 3 started providing the  libumem  tool (see     3.4.5 Using libumem to Find Leaks  ).
3.4.4 Using dbx to Find Leaks

The Sun debugger dbx includes the Run Time Checking (RTC) functionality, which can find leaks. The dbx debugger is also available on Linux.

Below is a sample dbx session.

$  
         dbx ${java_home}/bin/java
Reading java
Reading ld.so.1
Reading libthread.so.1
Reading libdl.so.1
Reading libc.so.1
(dbx)  
         dbxenv rtc_inherit on
(dbx)  
         check -leaks
leaks checking - ON
(dbx)  
         run HelloWorld
Running: java HelloWorld 
(process id 15426)
Reading rtcapihook.so
Reading rtcaudit.so
Reading libmapmalloc.so.1
Reading libgen.so.1
Reading libm.so.2
Reading rtcboot.so
Reading librtc.so
RTC: Enabling Error Checking...
RTC: Running program...
dbx: process 15426 about to exec("/net/bonsai.sfbay/export/home2/user/ws/j2se/build/solaris-i586/bin/java")
dbx: program "/net/bonsai.sfbay/export/home2/user/ws/j2se/build/solaris-i586/bin/java"
just exec'ed
dbx: to go back to the original program use "debug $oprog"
RTC: Enabling Error Checking...
RTC: Running program...
t@1 (l@1) stopped in main at 0x0805136d
0x0805136d: main       :        pushl    %ebp
(dbx)  
         when dlopen libjvm { suppress all in libjvm.so; }
(2) when dlopen libjvm { suppress all in libjvm.so; }  
(dbx)  
         when dlopen libjava { suppress all in libjava.so; }
(3) when dlopen libjava { suppress all in libjava.so; }  
(dbx) cont                                             
Reading libjvm.so
Reading libsocket.so.1
Reading libsched.so.1
Reading libCrun.so.1
Reading libm.so.1
Reading libnsl.so.1
Reading libmd5.so.1
Reading libmp.so.2
Reading libhpi.so
Reading libverify.so
Reading libjava.so
Reading libzip.so
Reading en_US.ISO8859-1.so.3
hello world
hello world
Checking for memory leaks...

Actual leaks report    (actual leaks:           27  total size:      46851 bytes)

  Total     Num of  Leaked     Allocation call stack
  Size      Blocks  Block
                    Address
==========  ====== =========== =======================================
     44376       4      -      calloc < zcalloc 
      1072       1  0x8151c70  _nss_XbyY_buf_alloc < get_pwbuf < _getpwuid <
                               GetJavaProperties < Java_java_lang_System_initProperties <
                               0xa740a89a< 0xa7402a14< 0xa74001fc
       814       1  0x8072518  MemAlloc < CreateExecutionEnvironment < main 
       280      10      -      operator new < Thread::Thread 
       102       1  0x8072498  _strdup < CreateExecutionEnvironment < main 
        56       1  0x81697f0  calloc < Java_java_util_zip_Inflater_init < 0xa740a89a<
                               0xa7402a6a< 0xa7402aeb< 0xa7402a14< 0xa7402a14< 0xa7402a14
        41       1  0x8072bd8  main 
        30       1  0x8072c58  SetJavaCommandLineProp < main 
        16       1  0x806f180  _setlocale < GetJavaProperties <
                               Java_java_lang_System_initProperties < 0xa740a89a< 0xa7402a14<
                               0xa74001fc< JavaCalls::call_helper < os::os_exception_wrapper 
        12       1  0x806f2e8  operator new < instanceKlass::add_dependent_nmethod <
                               nmethod::new_nmethod < ciEnv::register_method <
                               Compile::Compile #Nvariant 1 < C2Compiler::compile_method <
                               CompileBroker::invoke_compiler_on_method <
                               CompileBroker::compiler_thread_loop 
        12       1  0x806ee60  CheckJvmType < CreateExecutionEnvironment < main 
        12       1  0x806ede8  MemAlloc < CreateExecutionEnvironment < main 
        12       1  0x806edc0  main 
         8       1  0x8071cb8  _strdup < ReadKnownVMs < CreateExecutionEnvironment < main 
         8       1  0x8071cf8  _strdup < ReadKnownVMs < CreateExecutionEnvironment < main
      

The output shows that the dbx debugger reports memory leaks if memory is not freed at the time the process is about to exit. However, memory that is allocated at initialization time and needed for the life of the process is often never freed in native code. Therefore, in such cases the dbxdebugger can report memory leaks that are not leaks in reality.

Note that the example used two suppress commands to suppress the leaks reported in the virtual machine ( libjvm.so) and the Java support library ( libjava.so).

3.4.5 Using libumem to Find Leaks

Starting with Solaris 9 OS update 3, the libumem.so library and the modular debugger ( mdb) can be used to debug memory leaks. Before using libumem, you must preload the libumem library and set an environment variable as follows:

$  
         LD_PRELOAD=libumem.so
$  
         export LD_PRELOAD

$  
         UMEM_DEBUG=default
$  
         export UMEM_DEBUG
      

Now, run the Java application but stop it before it exits. The following example uses truss to stop the process when it calls the _exit system call:

$  
         truss -f -T _exit java MainClass  
         arguments
      

At this point you can attach the mdb debugger, as follows:

$  
         mdb -p  
         pid
>::findleaks
      

The ::findleaks command is the mdb command to find memory leaks. If a leak is found, thefindleaks command prints the address of the allocation call, buffer address, and nearest symbol.

It is also possible to get the stack trace for the allocation which resulted in the memory leak by dumping the bufctl structure. The address of this structure can be obtained from the output of the::findleaks command. The description of the commands to perform these functions, as well as more information on using libumem to identify memory managements bugs, is located at the following address: http://access1.sun.com/techarticles/libumem.html.




http://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java 

From the above link, there are some cases would cause memory-leak:


Static field holding object reference [esp final field]

class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}

Calling String.intern() on lengthy String

String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you cant remove
str.intern();

(Unclosed) open streams ( file , network etc... )

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

Unclosed connections

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}

Areas that are unreachable from JVM's garbage collector

like memory allocated through native methods

In web applications objects stored in application scope till application is restarted or removed explicitly

getServletContext().setAttribute("SOME_MAP", map);

In web applications objects stored session scope till its invalidated or removed explicitly

session.setAttribute("SOME_MAP", map);

Incorrect or inappropriate JVM options

like noclassgc option on IBM JDK that prevents unused class garbage collection



以上Link来自Oracle官方文档

http://www.oracle.com/technetwork/java/javase/memleaks-137499.html

还有其他link可以作为补充参考关于

http://www.javacodegeeks.com/2011/07/java-and-memory-leaks.html

http://www.ibm.com/developerworks/library/j-leaks/

http://stackoverflow.com/questions/37335/how-to-deal-with-java-lang-outofmemoryerror-java-heap-space-error-64mb-heap

http://stackoverflow.com/questions/6470651/creating-a-memory-leak-with-java


Java从1.6自带的两个用于观察内存定位问题的工具:Java VisualVM和Jconsole Utility

2.2 Java VisualVM

Java VisualVM is one of the tools included in the JDK download (starting with Java SE release 6 update 7). This tool is useful to Java application developers to troubleshoot applications and to monitor and improve the applications' performance. With Java VisualVM you can generate and analyze heap dumps, track down memory leaks, perform and monitor garbage collection, and perform lightweight memory and CPU profiling. The tool is also useful for tuning, heap sizing, offline analysis, and post-mortem diagnosis.

In addition, you can use existing plug-ins that expand the functionality of Java VisualVM. For example, most of the functionality of the JConsole tool is available via the MBeans tab and the JConsole plug-in wrapper tab. You can choose from a catalog of standard Java VisualVM plug-ins by choosing Plugins from the Tools menu in the main Java VisualVM window.

For comprehensive documentation for Java VisualVM, seehttp://java.sun.com/javase/6/docs/technotes/guides/visualvm/index.html

Java VisualVM allows you to perform the following troubleshooting activities:

View a list of local and remote Java applications.
View application configuration and runtime environment. For each application, the tool shows basic runtime information: PID, host, main class, arguments passed to the process, JVM version, JDK home, JVM flags, JVM arguments, system properties.
Enable and disable the creation of a heap dump when a specified application encounters an OutOfMemoryError  exception.
Monitor application memory consumption, running threads, and loaded classes.
Trigger a garbage collection immediately.
Create a heap dump immediately. You can then view the heap dump in several views: summary, by class, by instance. You can also save the heap dump to your local file system.
Profile application performance or analyze memory allocation (for local applications only). You can also save the profiling data.
Create a thread dump (stack trace of the application's active threads) immediately. You can then view the thread dump.
Analyze core dumps (with Solaris OS and Linux).
Analyze applications offline, by taking application snapshots.
Get additional plug-ins contributed by the community.
Write and share your own plug-ins.
Display and interact with MBeans (after installing the MBeans tab plug-in).

When you start Java VisualVM, the main Application window opens, displaying a list of Java applications running on the local machine, a list of Java applications running on any connected remote machines, a list of any VM core dumps that were taken and saved (with Solaris OS and Linux), and a list of any application snapshots that were taken and saved.

Java VisualVM will automatically detect and connect to JMX agents for Java applications that are running on version 6 of the Java SE platform or that have been started with the correct system properties on version 5.0. In order for the tool to detect and connect to the agents on a remote machine, the jstatd daemon must be running on the remote machine (see   2.13 jstatdDaemon ). In cases where Java VisualVM cannot automatically discover and connect to JMX agents that are running in a target application, the tool provides a means for you to explicitly create these connections.

2.3 JConsole Utility

Another useful tool included in the JDK download is the JConsole monitoring tool. This tool is compliant with Java Management Extensions (JMX). The tool uses the built-in JMX instrumentation in the Java Virtual Machine to provide information on the performance and resource consumption of running applications. Although the tool is included in the JDK download, it can also be used to monitor and manage applications deployed with the Java runtime environment.

The JConsole tool can attach to any Java SE application in order to display useful information such as thread usage, memory consumption, and details about class loading, runtime compilation, and the operating system.

This output helps with high-level diagnosis on problems such as memory leaks, excessive class loading, and running threads. It can also be useful for tuning and heap sizing.

In addition to monitoring, JConsole can be used to dynamically change several parameters in the running system. For example, the setting of the -verbose:gc option can be changed so that garbage collection trace output can be dynamically enabled or disabled for a running application.

The following list provides an idea of the data that can be monitored using the JConsole tool. Each heading corresponds to a tab pane in the tool.

Overview

This pane displays graphs showing, over time, heap memory usage, number of threads, number of classes, and CPU usage. This overview allows you to visualize the activity of several resources at once.

Memory

For a selected memory area (heap, non-heap, various memory pools):

Graph of memory usage over time
Current memory size
Amount of committed memory
Maximum memory size
Garbage collector information, including the number of collections performed, and the total time spent performing garbage collection.
Graph showing percentage of heap and non-heap memory currently used.

In addition, on this pane you can request garbage collection to be performed.

Threads

Graph of thread usage over time.
Live threads - Current number of live threads.
Peak - Highest number of live threads since the Java VM started.
For a selected thread, the name, state, and stack trace, as well as, for a blocked thread, the synchronizer that the thread is waiting to acquire and the thread owning the lock.
Deadlock Detection button - Sends a request to the target application to perform deadlock detection and displays each deadlock cycle in a separate tab.

Classes

Graph of number of loaded classes over time.
Number of classes currently loaded into memory.
Total number of classes loaded into memory since the Java VM started, including those subsequently unloaded.
Total number of classes unloaded from memory since the Java VM started.

VM Summary

General information, such as the JConsole connection data, uptime for the Java VM, CPU time consumed by the Java VM, complier name and total compile time, and so forth.
Thread and class summary information.
Memory and garbage collection information, including number of objects pending finalization, and so forth.
Information about the operating system, including physical characteristics, the amount of virtual memory for the running process, swap space, and so forth.
Information about the virtual machine itself, such as arguments, class path, and so forth.

MBeans

This pane displays a tree structure showing all platform and application MBeans that are registered in the connected JMX agent. When you select an MBean in the tree, its attributes, operations, notifications, and other information are displayed.

You can invoke operations, if any. For example, the operation  dumpHeap  for the HotSpotDiagnostic  MBean, which is in the  com.sun.management  domain, performs a heap dump. The input parameter for this operation is the pathname of the heap dump file on the machine where the target VM is running.
As another example of invoking an operation, you can set the value of writable attributes. For example, you can set, unset, or change the value of certain VM flags by invoking the setVMOption  operation of the  HotSpotDiagnostic  MBean. The flags are indicated by the list of values of the  DiagnosticOptions  attribute.
You can subscribe to notifications, if any, by using the Subscribe and Unsubscribe buttons.

JConsole can monitor both local applications and remote applications. If you start the tool with an argument specifying a JMX agent to connect to, the tool will automatically start monitoring the specified application.

To monitor a local application, execute the command jconsole pid, where pid is the process ID of the application.

To monitor a remote application, execute the command jconsole hostname : portnumber, wherehostname is the name of the host running the application, and portnumber is the port number you specified when you enabled the JMX agent.

If you execute the jconsole command without arguments, the tool will start by displaying the New Connection window, where you specify the local or remote process to be monitored. You can connect to a different host at any time by using the Connection menu.

With the J2SE 1.5 release, you must start the application to be monitored with the -Dcom.sun.management.jmxremote option. With the Java SE 6 release, no option is necessary when starting the application to be monitored.

As an example of the output of the monitoring tool, the following screen shows a chart of heap memory usage.

Sample Output from JConsole
Java Monitoring and Management Console (JConsole), Memory tab

A complete tutorial on the JConsole tool is beyond the scope of this document. However, the following documents describe in more detail the monitoring and management capabilities, and how to use JConsole:

Monitoring and Management for the Java Platform

http://java.sun.com/javase/6/docs/technotes/guides/management/index.html

Monitoring and Management Using JMX

http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html

Using JConsole

http://java.sun.com/javase/6/docs/technotes/guides/management/jconsole.html

Manual page for jconsole

http://java.sun.com/javase/6/docs/technotes/tools/share/jconsole.html



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值