OOM(Out-of-Memory)是导致应用服务器/JVM不稳定的常见问题。
OOM的一个重要原因是系统存在Java“内存泄漏”问题。
“内存泄漏”问题是对象的生命周期问题的一种。
可以理解为, 某些对象的生命周期过长,未及时清理,出现了“内存泄漏”。

查明为什么会发生“泄漏”的方法:
1. JVMTI
  Java虚拟机工具接口(Java Virtual Machine Tools Interface,JVMTI)
  及其前身Java虚拟机监视程序接口(Java Virtual Machine Profiling Interface,JVMPI)
  是外部工具与JVM通信并从JVM收集信息的标准化接口。

2. 字节码注入技术(byte code instrumentation)。
  字节码注入技术是指使用探测器处理字节码以获得工具所需信息的技术。

分析的具体步骤:
1. 进行趋势分析,找出是哪个类的对象在“泄漏”。
  每隔一段时间比较一次内存快照,如果存在实例个数保持增长的类,就可初步认定为存在内存“泄漏”。
2. 看看有哪些类与“泄漏”的类的对象相关联。
  Java中的内存泄漏就是保持对无用对象的引用,
  简单地说就是因为编码的错误导致了一条本来不应该存在的引用的存在(从而导致了被引用的对象无法释放)
  “内存泄漏”分析的任务就是找出这条多余的引用链,并找到其形成的原因。
3. 进一步研究单个可疑的“泄漏”对象,看看它们是如何互相关联的。
  借助于JProbe工具,可以跟踪自己应用代码中对象的创建堆栈,也可以对系统中所有对象分配进行堆栈跟踪。
  这些堆栈跟踪可以在工具中进行累积和分析。
  每个被“泄漏”的实例对象,必然存在一条从某个引用对象出发到达该对象的引用链。
  处于堆栈空间的引用对象在被从栈中弹出后就失去其引用,变为非引用对象。

Java中常见的“内存泄漏”类型:
1. 静态集合类:
  HashMap、Vector、ArrayList等静态集合类的使用最容易引起“内存泄漏”,
  因为这些静态变量的生命周期与应用程序一致,这些对象生命周期过长。
2. 监听器
  通常一个应用当中会用到很多监听器,
  我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,
  但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了“内存泄漏”的机会。
3. 物理连接
  比如数据库连接和网络连接,除非显式关闭了连接,否则是不会自动被GC 回收的。
4. 内部类和外部模块等的引用
  例如程序员A 负责A 模块,调用了B 模块的一个方法如:
    public void registerMsg(Object b);
  这种调用就要非常小心了,传入了一个对象,很可能模块B就保持了对该对象的引用,
  这时候就需要注意模块B 是否提供相应的操作去除引用。

参考:
http://www.innovatedigital.com/quest-jprobe-suitehttp://www.innovatedigital.com/node/788