前言

一般来说OOM指老年代无奈回收,而对象在不停的增长时,即JVM内存严重不足时,会抛出java.lang.OutOfMemoryError谬误,如果想设置程序主动dump,则须要动参数中指定-XX:+HeapDumpOnOutOfMemoryError来保留OOM时的dump文件

常见起因

  • <font color="rgb(53, 179, 120)">内存调配过小</font>,失常业务应用了大内存,比如说导出数据,1000条数据曾经达到500M,但-Xmx参数设置小于500M
  • 对象被一直创立,却没有开释,比如说HttpClient不必连接池,始终新建,却不敞开;线程创立也一样
  • io流操作文档没敞开流。
  • 往一个动态汇合变量里始终压栈。
  • 连贯没开释。
  • Java队列没耗费。
  • 频繁IO操作大文件。开启大型文件或从数据库一次拿了太多的数据很容易造成内存溢出,所以在这些中央要大略计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值

备注: 基本上就是内存资源不够,申请资源过大而且无奈开释

Java内存模型

Eden Space字面意思是伊甸园,对象被创立的时候首先放到这个区域,进行垃圾回收后,不能被回收的对象被放入到空的survivor区域。
Survivor Space幸存者区,用于保留在eden space内存区域中通过垃圾回收后没有被回收的对象。Survivor有两个,别离为To Survivor、 FromSurvivor,这个两个区域的空间大小是一样的。执行垃圾回收的时候Eden区域不能被回收的对象被放入到空的survivor(也就是To Survivor,同时Eden区域的内存会在垃圾回收的过程中全副开释),另一个survivor(即From Survivor)里不能被回收的对象也会被放入这个survivor(即To Survivor),而后To Survivor 和 From Survivor的标记会调换,始终保障一个survivor是空的。
Eden Space和Survivor Space都属于新生代,新生代中执行的垃圾回收被称之为Minor GC(因为是对新生代进行垃圾回收,所以又被称为Young GC),每一次Young GC后留下来的对象age加1。

Old Gen老年代,用于寄存新生代中通过屡次垃圾回收依然存活的对象,也有可能是新生代调配不了内存的大对象会间接进入老年代。通过屡次垃圾回收都没有被回收的对象,这些对象的年代曾经足够old了,就会放入到老年代。
当老年代被放满的之后,虚构机会进行垃圾回收,称之为Major GC。因为Major GC除并发GC外均需对整个堆进行扫描和回收,因而又称为Full GC。
heap区即堆内存,整个堆大小=年老代大小 + 老年代大小。堆内存默认为物理内存的1/64(<1GB);默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限度,能够通过MinHeapFreeRatio参数进行调整;默认空余堆内存大于70%时,JVM会缩小堆直到-Xms的最小限度,能够通过MaxHeapFreeRatio参数进行调整。

官网参考:
Java内存模型


这里分几局部,Heap Space(堆), Method Area(办法区),Navtive Area(本地区), Off Heap Space(堆外区)

堆内存寄存对象以及数组的数据,办法区寄存类的信息(包含类名、办法、字段)、动态变量、编译器编译后的代码,本地区蕴含线程栈、本地办法栈等寄存线程,办法区有时被称为长久代(PermGen)

Heap Space(堆)

  • 被所有线程共享
  • 存储数组与对象

Method Area(办法区)- JDK1.8后为元空间

  • 被所有线程共享
  • 它存储已被Java虚拟机加载的类信息、常量、动态变量、即时编译器编译后的代码等,Code Cache代码缓存区,它次要用于寄存JIT所编译的代码。CodeCache代码缓冲区的大小在client模式下默认最大是32m,在server模式下默认是48m,这个值也是能够设置的,它所对应的JVM参数为ReservedCodeCacheSize 和 InitialCodeCacheSize

本地区

  • 线程公有
  • 蕴含线程栈、本地办法栈等寄存线程

为了了解下面的阐明,举个例子

import java.text.SimpleDateFormat;import java.util.Date;import org.apache.log4j.Logger;public class HelloWorld {    private static Logger LOGGER = Logger.getLogger(HelloWorld.class.getName());    public void sayHello(String message) {        SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.YYYY");        String today = formatter.format(new Date());        LOGGER.info(today + ": " + message);    }}

Java GC基本知识

主动垃圾收集是查看堆内存,辨认正在应用的对象和未应用的对象以及删除未应用的对象的过程。应用中的对象或援用的对象,意味着程序的某些局部依然保护着指向该对象的指针。程序的任何局部都不再援用未应用的对象或未援用的对象。因而,能够回收未援用对象应用的内存。

在像C这样的编程语言中,调配和勾销分配内存是手动过程。在Java中,垃圾回收器会主动解决开释内存的过程。根本过程能够形容如下。

回收过程官网介绍

在Java语言里,可作为GC Roots对象的包含如下几种:

a.虚拟机栈(栈桢中的本地变量表)中的援用的对象 b.办法区中的类动态属性援用的对象 c.办法区中的常量援用的对象 d.本地办法栈中JNI的援用的对象

罕用定位问题命令

  • 首先定位到java程序的过程,用jps 命令
jps jps -v

  • 查看存活对象占用状况
jmap -histo:live 1| head -20


对象阐明:

- B byte- C char- D double- F float- I int- J long- Z boolean- [ 数组,如[I示意int[]- [L+类名 其余对象
  • 生产对堆快照Heap dump

jmap -dump:format=b,file=/tmp/过程号_jmap_dump.hprof 过程号

jmap -dump:live,format=b,file=/tmp/过程号_live_jmap_dump.hprof 过程号
  • jstat
#1s一次,共10次jstat -gcutil 1 1000  10#额定输入上次GC起因jstat -gccause 1

S0:幸存1区以后应用比例S1:幸存2区以后应用比例E:Eden Space(伊甸园)区应用比例O:Old Gen(老年代)应用比例M:元数据区应用比例CCS:压缩应用比例YGC:年老代垃圾回收次数FGC:老年代垃圾回收次数FGCT:老年代垃圾回收耗费工夫GCT:垃圾回收耗费总工夫

频繁GC问题或内存溢出问题

一、应用jps查看线程ID二、应用jstat -gc 3333 250 20 查看gc状况,个别比拟关注PERM区的状况,查看GC的增长状况。三、应用jstat -gccause:额定输入上次GC起因四、应用jmap -dump:format=b,file=heapDump 3333生成堆转储文件五、应用jhat或者可视化工具(Eclipse Memory Analyzer 、IBM HeapAnalyzer、JProfiler)剖析堆状况。六、联合代码解决内存溢出或泄露问题。

死锁问题

一、应用jps查看线程ID二、应用jstack 3331:查看线程状况