前言:
  C/C++的程序员渴望Java的自由, Java程序员期许C/C++的约束. 其实那里都是围城, 外面的人想进来, 里面的人想出去.

背景:
  作为Java程序员, 除了享受垃圾回收机制带来的便利外, 还深受OOM(Out Of Memory)的困惑和折磨. 本文借鉴了<<深入理解 Java虚拟机>>, 并结合了小编自身的经历和读者一起面对OOM的困局如何分析和破解.

准备工作:
  工欲善其事必先利其器, 对java进程的快照分析, 是能够帮助我们迅速的定位出错的原因. 这边我们着重介绍内存分析相关的点.
  借助MAT(Memory Analyzer Tool)来分析内存快照.
  MAT的下载地址:
  http://www.eclipse.org/mat/downloads.php
  eclipse的插件url:
  http://download.eclipse.org/mat/1.4/update-site/
  MAT的展示效果如图所示:

内存快照:
  如何去触发java进程生成内存快照呢?
  1). 设定jvm参数, 使得进程在特定条件下进程内存dump.

-XX:+HeapDumpOnOutOfMemoryError	

  评注: 设置如下虚拟机参数后, 当java进程因为内存溢出, 就会自动对内存进行Dump, 以便相关人员事后进行分析/解读.
  该方案非常具有针对性, 在崩溃点分析往往能立马定位问题的所在. 该参数设定方案相当于飞机的黑盒子, 记录了出事前所有信息.
  当然该方案, 最大的局限性就是不能随时随地进行分析, 那如何破呢?
  2). JMap工具来生成
  JMap的使用命令描述:

Usage:
  jmap [option] <pid>
    (to connect to running process)
  jmap [option] <executable <core>
    (to connect to a core file)
  jmap [option] [server_id@]<remote server IP or hostname>
    (to connect to remote debug server)

where <option> is one of:
  -dump:<dump-options> to dump java heap in hprof binary format
    dump-options:
    live	dump only live objects; if not specified,
          all objects in the heap are dumped.
    format=b binary format
    file=<file> dump heap to <file>
  Example: jmap -dump:live,format=b,file=heap.bin <pid>

  评注: 挑选了部分选项说明, 重要的是dump的规则
  使用命令如下所示:

jmap -dump:format=b,file=xxx.hprof <pid> 

OOM的原因分类:
  导致程序出现OOM的因素有多种. 大致我们可以把OOM简单的分为堆溢出(Heap), 栈溢出(Stack), 永久代溢出(常量池/方法区), 直接内存溢出.
  先来看下java的内存分布
  1). 堆溢出(heap)
  编写如下例程:

public static void main(String[] args) {
  List<byte[]> datas = new ArrayList<byte[]>();
  while ( true ) {
    datas.add(new byte[1024 * 1024]);
  }
}

  同时设置虚拟机参数, 使得java进程能够快速生成heapdump.

-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

  评注: 设置heap的内存限制在20m, Xms/Xmx分别对应heap的初始和最大heap大小.
  产生的异常信息:

  mat进行内存分析

  评注: 从这边能看出, 这边聚集了众多的对象, 占据了99%的内存量.
  2). 栈溢出(stack)
  栈溢出的异常, 还是具有明确的指向性的. 暂略.
  3). 永久代溢出(常量池/方法区)
  <<深入理解 Java虚拟机>>阐述了String.intern()和gclib产生动态代理类的两个例子.
  其错误也很有指向性:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

  这边讲述下, 小编(mumuxinfei)很久之前做的一个项目.
  当时是机顶盒项目(采用IPanel浏览器, 相当于jvm虚拟机), 采用J2ME规范(java 1.1). 不过当时的机器性能不好, 内存少, 不像现在, 一些移动设备配置开始像PC靠齐了.
  我把一些初始化数据放在类里声明并定义时, 编译没问题, 但是jvm无论如何也run不起来, 总是出错. 不过我把这些数据放在文件里时, 通过运行时载入, 这样就没问题. 当时的我特别疑惑, 不都是内存吗? 同样的数据, 同样的内存, 这么差别就这么大呢?
  当时的我不理解, 后来知道java的内存结构, 我就明白了. 载入的数据放在Heap中, 而定义的常量是放在PermGen空间中. 而当初的设备限制, IPanel浏览器的默认永久空间大小比较小, 导致我只要把一些数据写到常量中定义, 就运行失败.
  不过蛮荒时代, 总是过去了, 现在的机器配置, 你是不会遇到这么诡异的事了. 日子在一天一天的变好, 过去苦难的日子, 现在的小年轻, 你是不会懂的...
  4). 直接内存溢出
  <<深入理解 Java虚拟机>>讲述了DriectByteBuffer的例子. 当然最直接, 也是最容易遇到的, 还是JNI的使用, 搞Android开发的大拿故意能遇到. 这边也略过不讲.

后记:
  从某种角度来说, <<深入理解 Java虚拟机>>已经把OOM的原因和例子说得非常具体了, 小编难以去超越它, 也不愿简单的复制罗列抄袭之. 简单的描述, 权当作学习笔记了.

Java 性能优化实战记录(3)--JVM OOM的分析和原因追查的更多相关文章

  1. Java 性能优化实战记录(2)---句柄泄漏和监控

    前言: Java不存在内存泄漏, 但存在过期引用以及资源泄漏. (个人看法, 请大牛指正) 这边对文件句柄泄漏的场景进行下模拟, 并对此做下简单的分析.如下代码为模拟一个服务进程, 忽略了句柄关闭, ...

  2. Java 性能优化实战记录(1)---定位并分析耗cpu最多的线程

    1) jps    列出相关的java进程, 以及对应的pid    也可以使用如下命令来尝试    ps aux | grep java --color 2) top -Hp <pid> ...

  3. JVM——九大工具助你玩转Java性能优化

    本文转载自 http://www.importnew.com/12324.html 本文由 ImportNew - 陈 晓舜 翻译自 idrsolutions.欢迎加入翻译小组.转载请参见文章末尾的要 ...

  4. 《Java性能优化权威指南》

    <Java性能优化权威指南> 基本信息 原书名:Java performance 原出版社: Addison-Wesley Professional 作者: (美)Charlie Hunt ...

  5. 推荐:Java性能优化系列集锦

    Java性能问题一直困扰着广大程序员,由于平台复杂性,要定位问题,找出其根源确实很难.随着10多年Java平台的改进以及新出现的多核多处理器,Java软件的性能和扩展性已经今非昔比了.现代JVM持续演 ...

  6. Java 性能优化之 String 篇

    原文:http://www.ibm.com/developerworks/cn/java/j-lo-optmizestring/ Java 性能优化之 String 篇 String 方法用于文本分析 ...

  7. 读书笔记系列之java性能优化权威指南 一 第一章

    主题:java性能优化权威指南 pdf 版本:英文版 Java Performance Tuning 忽略:(0~24页)Performance+Acknowledge 1.Strategies, A ...

  8. Java 性能优化手册 — 提高 Java 代码性能的各种技巧

    转载: Java 性能优化手册 - 提高 Java 代码性能的各种技巧 Java 6,7,8 中的 String.intern - 字符串池 这篇文章将要讨论 Java 6 中是如何实现 String ...

  9. Java 性能优化的五大技巧

    要对你的 Java 代码进行优化,需要理解 Java 不同要素之间的相互作用,以及它是如何与其运行时的操作系统进行交互的.使用下面这五个技巧和资源,开始学习如何分析和优化你的代码吧. 在我们开始之前, ...

随机推荐

  1. Sql Server系列:聚合函数

    1 SUM SUM是一个求和函数,返回指定列值的总和.SUM 只能用于数字列. 其中忽略 Null 值. 语法 SUM ( [ ALL | DISTINCT ] expression ) OVER ( ...

  2. JAVA(3)

    接口注意事项: 1.接口不能被实例化 2.接口中所有的方法都不能有主体  (不能有{ }) 3.一个类可以实现多个接口 4.接口中可以有变量<但变量不能用private和protected修饰& ...

  3. mysql主主复制(双主复制)配置步骤

    以前我们介绍的都是主从复制,这里给各位介绍一个双主复制了,下面都希望两个主服务器数据自动复制的话可参考一下此文章.   MySQL主主复制结构区别于主从复制结构.在主主复制结构中,两台服务器的任何一台 ...

  4. android的充电图标显示

    最近RK3026的项目需要修改开机充电,才分析了Android原生态的充电过程. 充电的代码和图标在system/core/charger中,会编译成名字为charger的可执行文件,打包进ramdi ...

  5. Jenkins-测试自动化环境搭建(Python+RobotFramework+selenium)

    下载插件: Python:https://wiki.jenkins-ci.org/display/JENKINS/Python+Plugin RobotFramework:https://wiki.j ...

  6. glog摘记

    projcet url:https://code.google.com/p/google-glog/ usage: application-level logging setting flags GL ...

  7. 小波变换和motion信号处理(一)(转)

    写的太好,不得不转:http://www.kunli.info/2011/02/15/fourier-wavelet-motion-signal-1/ 这是<小波变换和motion信号处理> ...

  8. OOAD基本概念

    学习目标: 1.理解与掌握面向对象的概念与方法. 2.使用UML. 3.完成面向对象的分析与设计工作. 4.了解OO的设计原则及一些典型的设计模式 什么是面向对象? 面向对象(Object-Orien ...

  9. Elasticsearch5中安装Elasticsearch-head插件

    介绍 elasticsearch-head是一个用于管理Elasticsearch的web前端插件,搞过ES的同学应该都了解.该插件在es5中可以以独立服务的形式进行安装使用.本文将介绍如何操作. 相 ...

  10. springMVC_05结果跳转方式

    一.总结 总共有四个, 1.设置ModelAndView的值,根据view和视图解析器跳转到指定的页面 2.通过servletapi对象来实现,不需要视图解析器 3.通过springmvc来实现转发和 ...