Java OOM 常见情况
Java OOM 常见情况
原文:https://blog.csdn.net/qq_42447950/article/details/81435080
1)什么是OOM?
OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError。看下关于的官方说明: Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector. 意思就是说,当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error(注:非exception,因为这个问题已经严重到不足以被应用处理)。
2)为什么会OOM?
为什么会没有内存了呢?原因不外乎有两点:
1)分配的少了:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。
2)应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。
内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用。
内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。
在之前没有垃圾自动回收的日子里,比如C语言和C++语言,我们必须亲自负责内存的申请与释放操作,如果申请了内存,用完后又忘记了释放,比如C++中的new了但是没有delete,那么就可能造成内存泄露。偶尔的内存泄露可能不会造成问题,而大量的内存泄露可能会导致内存溢出。
而在Java语言中,由于存在了垃圾自动回收机制,所以,我们一般不用去主动释放不用的对象所占的内存,也就是理论上来说,是不会存在“内存泄露”的。但是,如果编码不当,比如,将某个对象的引用放到了全局的Map中,虽然方法结束了,但是由于垃圾回收器会根据对象的引用情况来回收内存,导致该对象不能被及时的回收。如果该种情况出现次数多了,就会导致内存溢出,比如系统中经常使用的缓存机制。Java中的内存泄露,不同于C++中的忘了delete,往往是逻辑上的原因泄露。
3)OOM的类型
JVM内存模型:
按照JVM规范,JAVA虚拟机在运行时会管理以下的内存区域:
- 程序计数器:当前线程执行的字节码的行号指示器,线程私有
- JAVA虚拟机栈:Java方法执行的内存模型,每个Java方法的执行对应着一个栈帧的进栈和出栈的操作。
- 本地方法栈:类似“ JAVA虚拟机栈 ”,但是为native方法的运行提供内存环境。
- JAVA堆:对象内存分配的地方,内存垃圾回收的主要区域,所有线程共享。可分为新生代,老生代。
- 方法区:用于存储已经被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Hotspot中的“永久代”。
- 运行时常量池:方法区的一部分,存储常量信息,如各种字面量、符号引用等。
- 直接内存:并不是JVM运行时数据区的一部分, 可直接访问的内存, 比如NIO会用到这部分。
按照JVM规范,除了程序计数器不会抛出OOM外,其他各个内存区域都可能会抛出OOM。
最常见的OOM情况有以下三种:
- java.lang.OutOfMemoryError: Java heap space ------>java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。
- java.lang.OutOfMemoryError: PermGen space ------>java永久代溢出,即方法区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。另外,过多的常量尤其是字符串也会导致方法区溢出。
- java.lang.StackOverflowError ------> 不会抛OOM error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。
4)OOM分析--heapdump
要dump堆的内存镜像,可以采用如下两种方式:
设置JVM参数-XX:+HeapDumpOnOutOfMemoryError,设定当发生OOM时自动dump出堆信息。不过该方法需要JDK5以上版本。
使用JDK自带的jmap命令。"jmap -dump:format=b,file=heap.bin <pid>" 其中pid可以通过jps获取。
dump堆内存信息后,需要对dump出的文件进行分析,从而找到OOM的原因。常用的工具有:
mat: eclipse memory analyzer, 基于eclipse RCP的内存分析工具。详细信息参见:http://www.eclipse.org/mat/,推荐使用。
jhat:JDK自带的java heap analyze tool,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言OQL,分析相关的应用后,可以通过http://localhost:7000来访问分析结果。不推荐使用,因为在实际的排查过程中,一般是先在生产环境 dump出文件来,然后拉到自己的开发机器上分析,所以,不如采用高级的分析工具比如前面的mat来的高效。
这个链接:http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html中提供了一个采用mat分析的例子 。
注意:因为JVM规范没有对dump出的文件的格式进行定义,所以不同的虚拟机产生的dump文件并不是一样的。在分析时,需要针对不同的虚拟机的输出采用不同的分析工具(当然,有的工具可以兼容多个虚拟机的格式)。IBM HeapAnalyzer也是分析heap的一个常用的工具。
Java 堆溢出
GC Roots 到对象之间有可达路径来避免垃圾回收机智清理这些对象 就会在对象数量达到最大堆的绒容量 然后产生内存溢出异常
Eclipse 的 Debug 页面中设置虚拟机参数
代码:
-verbose:gc -Xms20M -Xmx20M Xmn10M -XX:+PrintGCDaetails -XX:SurvivorRatio=8
JAVA堆的大小设置最小值 -Xms
JAVA堆的大小设置最大值 -Xmx
解决异常
首先通过内存映射分析工具 如 Eclipse Memory Analyzer 堆 dump出的异常堆转储进行快照解析确认内存中的对象是否是必要的 也就是先分清楚是 内存泄漏 Memory Leak 还是Memory Overflow 如果是内存泄漏 可通过工具进一步查看泄露的对象到GC Roots的引用链 就能找到泄露对象是怎么通过路径与 GC Roots 相关联导致垃圾收集器无法回收他们如果不存在泄露 就检查堆参数 -Xmx 与 -Xms 与机器物理内存对比是否还可以调大 从代码上检测 是否是某些对象的生命周期过长持有状态时间过长 尝试减少代码运行期间的内存消耗
虚拟机栈 和 本地方法栈 溢出
HotSpot 虚拟机不区分 虚拟机栈 和 本地方法栈 因此Xoss(设置本地方法栈内存大小)参数虽然存在但是是无效的
虚拟机栈 和 本地方法栈两种异常:
线程请求栈的深度大于虚拟机允许的最大深度 抛出 StackOverflowError
如果虚拟机在扩展栈是无法申请到足够的内存空间 抛出 Out Of Menmory Error
注:单个线程下 无论是栈帧太大还是虚拟机栈容量太小当内存无法分配的时候抛出的都是StackOverflowError
运行时常量池溢出
如果向运行时常亮去添加内容最简单的做法就是使用 String.intern() 这个 Narive 方法 该方法作用是如果池中包含一个等于此String对象的字符串 则返回代表池中这个字符串的 String 对象 否则将该 String 对象 的字符串添加到常量池中并返回此 String 对象的引用-XX:PermSize 方法区最小 -XX:MaxPermSize 方法区最大值如果运行时常量池 OOM 提示信息为 OutOfMemoryError : PermGen space 表示运行时常量池属于方法区的一部分
方法区溢出
方法区是用于存放 Class信息的 如类名 访问修饰符 常量池 等当前主流AOP框架 (Spring Hibernate 等) 都会使用到 CFLib 这类字节码技术对类进行加强 增强的类越多 就越需要越大的方法区来保证 动态生成的Class 可以载入内存在动态生成大量 Class 的应用中 需要特别注意类的回收状况 注:除了使用GCLib字节码增强意外 常见的还有 JSP 或者动态产生JSP的应用文件(JSP在第一次运行时要编译为JAVA类)或是基于 OSGi(注: OSGi(Open Service Gateway Initiative)技术是Java动态化模块化系统的一系列规范。OSGi一方面指维护OSGi规范的OSGI官方联盟,另一方面指的是该组织维护的基于Java语言的服务(业务)规范。简单来说,OSGi可以认为是Java平台的模块层。) 的应用即使是同一个类呗不同的加载器加载也会视为不同的类
本机直接内存溢出
DirectMemory 可通过-XX:MaxDirectMemorySize 指定 如果不指定则和JAVA堆的最大值一样使用DirectByteBuffer分配内存也会抛出内存溢出异常 但是他抛出异常的时候并没有向计算机申请分配内存 而是通过计算机内存得知是否可以分配于是抛出异常申请分配内存的方法是unsafe.allocateMemory();
================ End
Java OOM 常见情况的更多相关文章
- Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式
导致OutOfMemoryError异常的常见原因有以下几种: 内存中加载的数据量过于庞大,如一次从数据库取出过多数据: 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收: 代码中存在死循环 ...
- Java OOM学习
转载自原文: 什么是java OOM?如何分析及解决oom问题? 什么是OOM? OOM,全称"Out Of Memory",翻译成中文就是"内存用完了",表现 ...
- Java基础常见英语词汇
Java基础常见英语词汇(共70个) ['ɔbdʒekt] ['ɔ:rientid]导向的 ['prəʊɡræmɪŋ]编程 OO: object ...
- Java Socket常见异常处理 和 网络编程需要注意的问题
在java网络编程Socket通信中,通常会遇到以下异常情况: 第1个异常是 java.net.BindException:Address already in use: JVM_Bind. 该异常发 ...
- Java集合类常见的问题
本篇文章将尝试回答一些Java集合类常见的问题,以作知识梳理之用. ArrayList和LinkList以及Vector的区别 就实现方式而言: ArrayList是以数组的方式实现的列表. Link ...
- Java英文单词Java基础常见英语词汇
Java英文单词Java基础常见英语词汇(共70个) ...
- Java总结——常见Java集合实现细节(1)
Java提高——常见Java集合实现细节(1) 2018年04月18日 15:07:35 阅读数:25 集合关系图 Set和Map set代表一种集合元素无序.集合元素不可重复的集合 map代表一种由 ...
- Java 最常见的 200+ 面试题:面试必备
这份面试题,包含的内容了十九了模块:Java 基础.容器.多线程.反射.对象拷贝.Java Web 模块.异常.网络.设计模式.Spring/Spring MVC.Spring Boot/Spring ...
- Android内存优化10 内存泄漏常见情况1 静态泄漏
1,内存泄漏到本质是该释放的对象被持久化的对象引用了,造成持久化的常见情况有1,静态持久化 2,线程持久化 线程持久化 因为存活的线程是有dvk虚拟久直接持有,所以存活的线程都是持久化的 内存泄漏1: ...
随机推荐
- android 环境的配置
经过了长达好几天的她探索,一直出现各种问题,然后,也是一个一个的解决,但最后,解决烦了,就觉得重新开始配置android的环境了. 原来一直都是版本的问题,因为我之前下载的都是2014的版本,而这个版 ...
- Luogu3350 ZJOI2016 旅行者 最短路、分治
传送门 题意:给出一个$N \times M$的网格图,边有边权,$Q$组询问,每组询问$(x_1,y_1)$到$(x_2,y_2)$的最短路.$N \times M \leq 2 \times 10 ...
- 一个可爱 & 小清新的加载等待Android控件
https://github.com/Carson-Ho/Kawaii_LoadingView
- 记一次网页超时登录的Bug
前几天,在做全公司的员工测评工作,在一个页面弹出导入页面,并导入所有评价记录,然后关闭掉这个导入页面,最后返回当前页面,返回时刷新当前页面. 在返回的时候,就出现了“页面超时登录”同时返回登录首页的问 ...
- gist.github.com 被墙无法访问解决办法
windows下 打开C:\Windows\System32\drivers\etc\hosts文件 编辑器打开,在最后行添加192.30.253.118 gist.github.com 保存.
- FreeRTOS 任务与调度器(1)
前言: Task.c和Task.h文件内是FreeRTOS的核心内容,所有任务和调度器相关的API函数都在这个文件中,它包括下图这些内容FreeRTOS文件如下: Task.c和Task.h文件内是F ...
- Spring+SpringMVC+MyBatis+easyUI整合进阶篇(六)一定要RESTful吗?
作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载. 写在前面的话 这个问题看起来就显得有些萌,或者说类似的问题都有些不靠 ...
- jackjson-databind-2.9.3 笔记
问题 客户端请求: {"skip":0,"take":10,"corpName":"","cityCode&q ...
- 通过容器提交镜像(docker commit)以及推送镜像(docker push)笔记
在本地创建一个容器后,可以依据这个容器创建本地镜像,并可把这个镜像推送到Docker hub中,以便在网络上下载使用. 查看镜像 [root@docker-test1 ~]# docker image ...
- Centos6.9下安装并使用VNC的操作记录
VNC是一个的"远程桌面"工具.,通常用于“图形界面”的方式登录服务器,可视化操作.废话不多说了,操作记录如下: 1)安装桌面环境 [root@vm01 ~]# yum -y gr ...