关于 OutOfMemoryError 的总结与解决方法

引言

本文总结自周志明的《深入理解Java虚拟机》第二章部分内容。

这部分内容,可以为后续性能调优方面的工作起到铺垫作用。

一、什么是 OutOfMemoryError

OurOfMemory 简称“OOM”, 直译为“内存耗尽”或“内存溢出”,当然,并不是真的内存耗尽了,它指的是 JVM 的几个逻辑分区的内存不够用了,无法为新的对象分配空间。

在 JVM 的几个主要内存分区中(JVM 栈、本地方法栈、计数器、方法区、Java 堆),只有计数器不会出现这种严重错误,也就是说,我们常说的堆和栈等,都有可能出现 OOM 的问题

二、Java 堆溢出

由于 Java 中最常见的内存分配就是对象,因此,经常要分配内存用于创建对象的堆区,是出现OOM问题的最常见内存分区。

对于 Java 堆的内存溢出,原因其实非常简单。因为堆是用于存储对象的,因此只要不断地创建对象,并且保证 GC Roots 到对象之间有可达路径避免垃圾回收机制清除这些对象,那么堆就必然会出现 OOM 问题。

如果要试验堆上的 OOM ,最快的方法就是将堆的分配大小调的低一些,并且不可扩展。

跟在 java 启动指令之后的两个最基本的堆大小分配参数是:-Xms 最小堆内存-Xmx 最大堆内存将这两个参数的值设置为相同,即可避免堆内存的自动扩展

案例演示

案例使用 JDK 1.8 ,IDE是 Eclipse,内存分析工具Eclipse Memory Analyzer(简称 MAT)(https://www.eclipse.org/mat/downloads.php)

使用如上图所示的虚拟机参数执行程序,即可发生堆内存的 OOM 错误。-XX:+HeapDumpOnOutOfMemoryError 参数可以让虚拟机在出现内存溢出时Dump(转储;倾倒)出当前的内存堆转储快照,以便事后进行分析。

dump文件的名称类似: java_pid31228.hprof,需要使用 MAT 打开并分析。(具体分析过程暂时不做详细介绍)

总之,当出现堆溢出时,一般的手段是,先通过内存映像分析工具(如Eclipse Memory Analyzer)对 Dump 出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

内存泄漏,表示对象已经无用,但是GC并没有回收,需要进一步通过工具查看泄漏对象到 GC Roots 的引用链,掌握了泄漏对象的类型信息GC Roots 引用链 信息,就可以比较准确地定位出泄漏代码的位置。而内存溢出

内存溢出,表示对象却是还存活着,导致GC 无法回收“有用的”对象,因此就需要检查 堆参数(-Xms 、-Xmx),与机器物理内存对比看是否还可以调大,或者从代码上检查,是否有对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

三、虚拟机栈溢出

在 HotSpot 虚拟机中是不区分 JVM 栈和本地方法栈的。设置本地方法栈大小的参数 -Xoss 实际上并无效果

栈容量只由 -Xss 参数设定。

Java 虚拟机规范规定了两种栈异常:

1、如果线程请求的栈深度大于虚拟机所允许的最大深度,抛出 StackOverflowError 异常。

2、如果虚拟机在扩展栈时无法申请到足够的内存空间,抛出 OutOfMemoryError 异常。

实际上,StackOverflowError 针对的是单独的虚拟机栈,而 OutOfMemoryError 则描述的是所有虚拟机栈。因为一个应用程序中很可能存在多个线程,因此这样区分异常可能是为了更精确的描述出现的问题。

相对来说,虚拟机栈内存出现问题多数都是 StackOverflowError,而且,Overflow的话会有错误堆栈可以阅读,相对比较好找到问题所在。而且,如果使用虚拟机默认参数,栈深度在大多数情况下,达到1000 到 2000 个栈帧完全没有问题。对于正常的方法调用和递归,这个深度应该完全够用。

因此,如果虚拟机栈发生 OOM ,很可能是由于栈深度过大,换句话说,-Xss 参数值过大。

案例演示

以下代码可能在Windows上运行会使系统假死,建议将重要文件和工作保存。

由于我的电脑本身执行上面的程序就会出现操作系统假死,因此这里贴出书中的执行结果:

   Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

四、方法区和运行时常量池溢出

运行时常量池是方法区的一部分,因此,可以通过常量池溢出来测试这两个区域的溢出情况。

上面的代码通过 CGLib 动态生成大量的 Class 加载如 方法区。需要通过maven引入CGLib依赖:

		<!-- https://mvnrepository.com/artifact/cglib/cglib --><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.5</version></dependency>

但是代码执行后并未出现方法区内存溢出的问题。书中贴出的方法区内存溢出异常报错如下:

Caused by:java.lang.OutOfMemoryError : PermGen spaceat ...at ...at ...

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558703.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows误关闭资源管理器重启的办法

引言 有时候Windows系统在开机后&#xff0c;在桌面底部的任务栏中无法正常加载必要的网络连接图标或音量图标等&#xff0c;导致无法手动操作音量或连接网络。这时候就会需要打开“任务管理器”重新启动“资源管理器”使其重新加载这些必要的控制图标。 但是由于操作失误&am…

MySQL高级 —— 高性能索引

引言 最近一直在抱着《高性能MySQL&#xff08;第三版&#xff09;》研究MySQL相关热点问题&#xff0c;诸如索引、查询优化等&#xff0c;这阶段的学习是前一段时间MySQL基础与官方的“阅读理解”的进一步延伸。 书中第五章详细阐述了如何设计高性能的索引&#xff0c;以及索…

MySQL高级 —— 查询性能优化

引言 承接《MySQL高级 —— 高性能索引》&#xff0c;本篇博客将围绕《高性能MySQL&#xff08;第三版&#xff09;》第六章内容进行总结和概括。 与索引的部分一样&#xff0c;SQL优化也是广大程序员深入MySQL的又一条必经之路。希望通过本篇博客的总结&#xff0c;能够为我…

Java常用设计模式————适配器模式

引言 由于无法直接使用某个类中的方法而采取的一种中间类转换的策略。将一个类的接口转换成另一个接口&#xff0c;让原本接口不兼容的类可以兼容。 适配器模式可以分为三种&#xff1a;类适配器、对象适配器、接口适配器。它们之间的区别主要体现在适配器角色与被适配角色之…

Java常用设计模式————桥接模式

引言 在实际的业务中&#xff0c;经常会遇到多维度的概念组合&#xff0c;公园的门票&#xff0c;颐和园有年票、月票、日票&#xff0c;故宫也有年票、月票、日票。那么不同的公园和票种类型就可以视为两种不同的纬度&#xff0c;它们之间会形成相互组合的关系。 在类的设计…

Java常用设计模式————装饰者模式

引言 装饰者模式&#xff0c;又叫装饰器模式。它可以动态的将新功能附加到对象上。在对象功能扩展方面&#xff0c;它比继承更灵活&#xff0c;同时装饰者模式也体现了OCP原则。 在客户端调用使用了装饰者模式的对象时&#xff0c;就好像在使用构造器层层包裹核心对象&#x…

Java常用设计模式————组合模式

引言 组合模式&#xff0c;是一种类似递归算法的结构性设计模式&#xff0c;通过以简单的 List &#xff0c;组合本类对象&#xff0c;实现树状对象结构的“部分、整体”的层次。 它可以让调用程序不需要关心复杂对象与简单对象的区别&#xff0c;而统一地实现处理逻辑。 对…

Java常用设计模式————外观模式

引言 外观模式&#xff08;Facade Pattern&#xff09;&#xff0c;又叫“过程模式”。外观模式为子系统中的一组接口提供一个一致的入口&#xff0c;此模式定义了一个高层接口&#xff0c;这个接口使得这一组子系统更加易用。 一、案例分析 生活中有很多类似的案例&#xf…

Java常用设计模式————享元模式

引言 享元模式&#xff0c;也叫蝇量模式&#xff08;Flyweight Pattern&#xff09;。运用共享技术有效地支持大量细粒度的对象。 享元模式常用于系统底层开发&#xff0c;解决系统的性能问题。例如数据库连接池&#xff0c;里面都是创建好的连接对象&#xff0c;在这些连接对…

IDEA——常用基础设置

一、设置入口 File—>Settings... 或者 在工具栏的“小扳手”图标。 二、主题设置 三、编辑通用设置 设置面板中的 Editor 3.1 自动导包 可以设置IDEA自动为程序导包&#xff0c;在书写时加入准确的导包&#xff0c;在书写时优化导包&#xff08;自动去掉未使用的&#…

IDEA——常用快捷键

引言 总结 IDEA 的常用快捷键&#xff0c;除了部分快捷键与 Eclipse 保持一致之外&#xff0c;枚举更多的实用快捷键。 一、如何设置快捷键 在 Settings -> Keymap 中&#xff0c;下拉框里选择 Eclipse &#xff0c;即可将 IDEA 的快捷键设置为与 Eclipse 保持一致。但并…

IDEA——常用代码模板

引言 IDEA 提供了一些内置的代码模板&#xff0c;可以让开发者快速方便的使用&#xff0c;当然 eclipse 中也是有的&#xff0c;比如输入 syso 快速生成输出语句&#xff0c;main 快速生成主函数等。 idea 的模板设置都在 Settings --> Live Templates 和 General-->Po…

IDEA——Git 的设置与使用

引言 在本机下载好 Git 之后&#xff0c;再去在 IDEA 中设置 Git 相关的参数。详细的 Git 操作和 Eclipse 大同小异&#xff0c;可以移步至&#xff1a;《Git必知必会》 一、设置Git执行程序路径 二、导入一个新的远程 git 托管项目 打开 File ——> New ——> Project…

IDEA——Maven的配置与使用

引言 简单介绍一下如何在 idea 中配置maven&#xff0c;以及如何去使用 maven 。 一、配置 Maven home Maven home 和 settings 文件一般都需要进行重新设置&#xff0c;关联到本机已经安装好的 maven 版本&#xff0c;settings 这里可以使用默认&#xff0c;也可以设置为 ma…

Spring Cloud Alibaba——Nacos实现服务治理

引言 本博客总结微服务开发中各个微服务调用的实现&#xff0c;并使用 Nacos 完成服务注册和发现。 文章中会涉及到 maven 的使用&#xff0c;以及 spring boot 的一些知识。开发工具采用 IDEA 2020.2。 设计一个电商订单和商品购买微服务&#xff0c;实现微服务的注册发现与…

Spring Cloud —— Feign 实现服务调用

引言 本篇博客简单介绍 Feign 的基础知识和基本应用&#xff0c;以前一篇博客《Spring Cloud Alibaba——Nacos实现服务治理》为代码基础&#xff0c;实现更简单的微服务调用方式。 一、什么是Feign restTemplate 实现的微服务调用方式&#xff1a; // 调用商品微服务&…

Spring Cloud —— 负载均衡与 Ribbon 应用

引言 本篇博客简单介绍微服务负载均衡的概念&#xff0c;并通过 IDEA 多端口启动应用的方式&#xff0c;模拟多个应用实例&#xff0c;使用自定义和 Ribbon 两种方式实现基本的负载均衡策略。 微服务代码以《Spring Cloud Alibaba——Nacos实现服务治理》为基础。 一、什么是…

Spring —— 容器内部逻辑

引言 上一篇关于IoC容器的详解《Spring —— IoC 容器详解》真是工程浩大&#xff0c;可以说Spring官网对核心中的核心IOC容器做了非常全面的使用说明&#xff0c;包括在《Spring揭秘》中让我一直没有成功的Method Injection&#xff0c;官网也解决了我的疑惑&#xff0c;并最…

2020 年度总结

2020年给我的感觉是短平快的一年。 由于年初的新冠肺炎疫情&#xff0c;我大半年都呆在北京的破旧出租屋里写代码。整个春天和夏天&#xff0c;平平无奇。 2月1日返京&#xff0c;居家办公&#xff0c;夜跑。8月复工&#xff0c;疯狂爆痘、烂脸&#xff0c;月末落户天津。9月…

JDBC——概述与JDBC的使用

引言 一直希望深入学习一下数据库持久化技术&#xff0c;接触过Hibernate、Mybatis&#xff0c;也使用过Spring事务管理来控制回滚操作&#xff0c;但是越发觉得底层知识有一定的知识盲区和空洞。 很多ORM框架都是基于JDBC规范来进行构建的&#xff0c;因此&#xff0c;学习J…