错误处理方法 java_JAVA常见错误处理方法 和 JVM内存结构

OutOfMemoryError在开发过程中是司空见惯的,遇到这个错误,新手程序员都知道从两个方面入手来解决:一是排查程序是否有BUG导致内存泄漏;二是调整JVM启动参数增大内存。OutOfMemoryError有好几种情况,每次遇到这个错误时,观察OutOfMemoryError后面的提示信息,就可以发现不同之处,如:

java.lang.OutOfMemoryError: Java heap space

java.lang.OutOfMemoryError: unable to create new native thread

java.lang.OutOfMemoryError: PermGen space

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

虽然都叫OutOfMemoryError,但每种错误背后的成因是不一样的,解决方法也要视情况而定,不能一概而论。只有深入了解JVM的内存结构并仔细分析错误信息,才有可能做到对症下药,手到病除。

JVM规范

JVM规范对Java运行时的内存划定了几块区域(详见这里),有:JVM栈(Java Virtual Machine Stacks)、堆(Heap)、方法区(Method Area)、常量池(Runtime Constant Pool)、本地方法栈(Native Method Stacks),但对各块区域的内存布局和地址空间却没有明确规定,而留给各JVM厂商发挥的空间。

HotSpot JVM

Sun自家的HotSpot JVM实现对堆内存结构有相对明确的说明。按照HotSpot JVM的实现,堆内存分为3个代:Young Generation、Old(Tenured) Generation、Permanent Generation。众所周知,GC(垃圾收集)就是发生在堆内存这三个代上面的。Young用于分配新的Java对象,其又被分为三个部分:Eden Space和两块Survivor Space(称为From和To),Old用于存放在GC过程中从Young Gen中存活下来的对象,Permanent用于存放JVM加载的class等元数据。详情参见HotSpot内存管理白皮书。堆的布局图示如下:

395fc36e9ed9ceb69903e64ac76a1a3e.png

根据这些信息,我们可以推导出JVM规范的内存分区和HotSpot实现中内存区域的对应关系:JVM规范的Heap对应到Young和Old Generation,方法区和常量池对应到Permanent Generation。对于Stack内存,HotSpot实现也没有详细说明,但HotSpot白皮书上提到,Java线程栈是用宿主操作系统的栈和线程模型来表示的,Java方法和native方法共享相同的栈。因此,可以认为在HotSpot中,JVM栈和本地方法栈是一回事。

操作系统

由于一个JVM进程首先是一个操作系统进程,因此会遵循操作系统进程地址空间的规定。32位系统的地址空间为4G,即最多表示4GB的虚拟内存。在Linux系统中,高地址的1G空间(即0xC0000000~0xFFFFFFFF)被系统内核占用,低地址的3G空间(即0×00000000~0xBFFFFFFF)为用户程序所使用(显然JVM进程运行在这3G的地址空间中)。这3G的地址空间从低到高又分为多个段;Text段用于存放程序二进制代码;Data段用于存放编译时已初始化的静态变量;BSS段用于存放未初始化的静态变量;Heap即堆,用于动态内存分配的数据结构,C语言的malloc函数申请的内存即是从此处分配的,Java的new实例化的对象也是自此分配。不同于前面三个段,Heap空间是可变的,其上界由低地址向高地址增长。内存映射区,加载的动态链接库位于这个区中;Stack即栈空间,线程的执行即是占用栈内存,栈空间也是可变的,但它是通过下界从高地址向低地址移动而增长的。详情参见这里。图示如下:

348829c78f91d41b227267c2db3b45ac.png

JVM本身是由native code所编写的,所以JVM进程同样具有Text/Data/BSS/Heap/MemoryMapping/Stack等内存段。而Java语言的Heap应当是建立在操作系统进程的Heap之上的,Java语言的Stack应该也是建立操作系统进程Stack之上的。 综合HotSpot的内存区域和操作系统进程的地址空间,可以大致得到下列图示:

135ad3cae78f73d0a53186db1a235102.png

Java线程的内存是位于JVM或操作系统的栈(Stack)空间中,不同于对象——是位于堆(Heap)中。这是很多新手程序员容易误解的地方。注意,“Java线程的内存”这个用词不是指Java.lang.Thread对象的内存,java.lang.Thread对象本身是在Heap中分配的,当调用start()方法之后,JVM会创建一个执行单元,最终会创建一个操作系统的native thread来执行,而这个执行单元或native thread是使用Stack内存空间的。

经过上述铺垫,可以得知,JVM进程的内存大致分为Heap空间和Stack空间两部分。Heap又分为Young、Old、Permanent三个代。Stack分为Java方法栈和native方法栈(不做区分),在Stack内存区中,可以创建多个线程栈,每个线程栈占据Stack区中一小部分内存,线程栈是一个LIFO数据结构,每调用一个方法,会在栈顶创建一个Frame,方法返回时,相应的Frame会从栈顶移除(通过移动栈顶指针)。在这每一部分内存中,都有可能会出现溢出错误。回到开头的OutOfMemoryError,下面逐个说明错误原因和解决方法(每个OutOfMemoryError都有可能是程序BUG导致,因此解决方法不包括对BUG的排查)。

java.lang.OutOfMemoryError: Java heap space

原因:Heap内存溢出,意味着Young和Old generation的内存不够。

解决:调整java启动参数 -Xms -Xmx 来增加Heap内存。

java.lang.OutOfMemoryError: unable to create new native thread

原因:Stack空间不足以创建额外的线程,要么是创建的线程过多,要么是Stack空间确实小了。

解决:由于JVM没有提供参数设置总的stack空间大小,但可以设置单个线程栈的大小;而系统的用户空间一共是3G,除了Text/Data/BSS/MemoryMapping几个段之外,Heap和Stack空间的总量有限,是此消彼长的。因此遇到这个错误,可以通过两个途径解决:1.通过-Xss启动参数减少单个线程栈大小,这样便能开更多线程(当然不能太小,太小会出现StackOverflowError);2.通过-Xms -Xmx 两参数减少Heap大小,将内存让给Stack(前提是保证Heap空间够用)。

java.lang.OutOfMemoryError: PermGen space

原因:Permanent Generation空间不足,不能加载额外的类。

解决:调整-XX:PermSize= -XX:MaxPermSize= 两个参数来增大PermGen内存。一般情况下,这两个参数不要手动设置,只要设置-Xmx足够大即可,JVM会自行选择合适的PermGen大小。

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

原因:这个错误比较少见(试着new一个长度1亿的数组看看),同样是由于Heap空间不足。如果需要new一个如此之大的数组,程序逻辑多半是不合理的。

解决:修改程序逻辑吧。或者也可以通过-Xmx来增大堆内存。

在GC花费了大量时间,却仅回收了少量内存时,也会报出OutOfMemoryError,我只遇到过一两次。当使用-XX:+UseParallelGC或-XX:+UseConcMarkSweepGC收集器时,在上述情况下会报错,在HotSpot GC Turning文档上有说明:

The parallel(concurrent) collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown.

对这个问题,一是需要进行GC turning,二是需要优化程序逻辑。

java.lang.StackOverflowError

原因:这也内存溢出错误的一种,即线程栈的溢出,要么是方法调用层次过多(比如存在无限递归调用),要么是线程栈太小。

解决:优化程序设计,减少方法调用层次;调整-Xss参数增加线程栈大小。

本文转自

http://blog.csdn.net/xiaoyufu007/article/details/6429657

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

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

相关文章

java中如何分隔字符串_Java中分割字符串

java.lang.String的split()方法, JDK 1.4 or laterpublic String[] split(String regex,int limit)示例代码public classStringSplit {public static voidmain(String[] args) {String sourceStr "1,2,3,4,5";String[] sourceStrArray sourceStr.split(",&quo…

php测试号推送消息失败,信息发送失败是什么原因

手机突然信息发送失败可能是以下原因:1.是因为我们的手机出现了欠费的情况,所以发不出短信,这种情况是最为普遍的,需要我们及时的进行缴费。2.手机的信息中心的号码设置有误,应该根据你所在省份的实际信息中心号码进行设置,这样一般就能解决这方面的问题。可能是你的…

php ajax 概率 转盘,php+jquery实现转盘抽奖 概率可任意调

phpjquery实现转盘抽奖 概率可任意调phpjquery实现转盘抽奖 概率可任意调Posted by: xiaomiao 2014/05/13in Code, PHP 3 Commentsphpjquery实现转盘抽奖查看DEMO演示转盘抽奖,炫丽的一般是flash做的。不懂flash而又不需要那么炫丽,可以简单的通过jquer…

php自动抓取文章图片,从文章中提取图片,把图片保存到本地,自动提取缩略图...

开发二代旅游网站程序和CMS的时候,有一个需求,就是从网上复制的内容,里面包含图片的,需要对把图片提取出来,并且保存到本地,并且把图片的URL地址本地化,以下是实现的代码。开发二代旅游网站程序…

简单的php探针,php探针程序的推荐

在我们之前的文章已经为大家介绍了什么是php探针,以及他的主要作用是什么,如果你接触了cms或许就会有点了解,当然,不要紧,看完这篇就知道php探针是做什么的了。php探针通常是用来探测空间、服务器运行的状况和php相关信…

php熊掌号怎么设置json-ld,dedecms织梦系统对接百度熊掌号并添加JSON_LD数据

百度近期推出的百度熊掌号非常的不错,我的dedecms织梦系统早早就对接好了,它能对你的原创文章进行原创保护,并评出熊掌号搜索指数,熊掌号搜索指数是对你文章的内容质量,用户喜爱、原创能力、活跃表现、领域专注五个维度进行计算评估而得到的。你的dedecms织梦网站开通熊掌号之后…

php获取信息,PHP文件信息获取函数

知识点:basename():获取文件名,传入第二个参数则只显示文件名,不显示后缀dirname():获取文件路径pathinfo():将文件信息存入一个数组,通过索引basename,dirname,extension可以获得对应的文件名,…

mysql pdo 查询一条数据,使用 PDO 关联查询 MySQL 数据

使用pdo关联查询mysql数据try {$pdo new PDO(mysql:hostlocalhost;dbnametest;, root, 123456);// 0.等值联结$sql SELECT c.name, o.id, o.customer_id, o.price FROM orders o, customer c WHERE o.customer_id c.id AND c.name :name;// 1.内联结(与上面等值联结返回的查…

mysql 数据类型怎么用,myMySQL数据库怎么更改表中某字段的数据类型? MySQL数据库使用教程...

在mysql中,可以使用“ALTER TABLE”语句配合“MODIFY”关键字来更改表中某字段的数据类型;语法格式“ALTER TABLE MODIFY ”。(推荐教程:mysql视频教程)在 MySQL 中,ALTER TABLE 语句可以改变原有表的结构,例如增加或删…

matlab multithreading spyder,spyder和python的关系是什么

版权所有:http://wWw.pxcodeS.comspyder和python的关系:1、Spyder是Python的一个简单的集成开发环境;2、它和其他的Python开发环境相比**大的优点就是模仿MATLAB的“工作空间”的功能,可以很方便地观察和修改数组的值。LHF少儿编程…

python私有成员和保护成员,喜大普奔!Maya 2022来了?!

距离Maya 2020第一个版本发布已经过去将近1年半。各位用户苦等Maya 2021的发布,不料2021没等到,而Maya 2022要来了?!这两天小编刷Maya官网,在帮助页面竟然看到官方放出了“Maya 2022 新特性”的页面!吓得小…

php web教程视频教程下载,Web全栈 PHP+React系列视频教程下载

Web全栈 PHPReact系列视频教程下载课程介绍:此套Web全栈 PHPReact系列视频教程覆盖PHP、前端和区块链应用开发三大热门职位,教程对网络基础、前端基础(HTML CSSJavaScriptjQuery)、网站基础、PHP、React、区块链等均做了详细的讲解,无源码。Web全栈 PHPR…

mac怎么配置php开发环境变量,Mac M1安装mnmp(Mac+Nginx+MySQL+PHP)开发环境

之前刚装好了 HomeBrew ,接下来就要安装 环境了。注意:如果 brew install 出以下错误, 则安装时使用arch -arm64 brew install软件包名 进行安装安装 Nginxbrew install nginx安装成功后,通过 brew info nginx ,查看 nginx 信息,最主要是看 网…

php5 dm.dll,win10模块dll加载失败二进制怎么解决?

首先使用【WinR】,打开运行窗口,输入“Powershell”,并回车;然后在打开的Powershell管理器中,输入“Get-AppXPackage -AllUsers | Foreach {....}”命令;最后等待系统自行处理即可解决方法:1、我…

oracle将千万行查询优化到一秒内,oracle下一条SQL语句的优化过程(比较详细)

oracle下一条SQL语句的优化过程(比较详细)更新时间:2010年04月14日 23:56:49 作者:很简单的一次调整,语句加了适当的索引后性能就有大幅的提升。当时看到这条语句的时候,第一感觉就是执行效率肯定低下。语句的功能是求某一客户当…

oracle tb级别数据量,备份TB级别Oracle数据库的一些技巧

备份TB级别数据的一些技巧1、 考虑使用增量备份, 不要老是想着用全量备份2、 对于增量备份而言 开启block change tracking 能极大地减少物理读,提升速度3、 11g以后对于bigfile tablespace可以启用section size 来提升速度4、 考虑到负载更低的 Data Gu…

oracle ora 47306,Oracle SQL提示含义与示例 --- 分布式查询和并行提示

《Oracle 高性能SQL引擎剖析:Oracle SQL 优化与调优技术详解》一书的附录部分。作为对该书的补充,帮助读者理解和掌握“提示”这一项在SQL优化中使用的这一重要辅助手段。语法:DRIVING_SITE([])描述:指示优化器选择那个数据库作为…

linux看网络电影,Linux中看电影、听音乐

Linux中看电影,听音乐目录:一、简介二、软件安装三、简单使用一、简介一直以来很多人不使用Linux作为自己的日常操作系统,是因为Linux在多媒体方面的应用不给力,现在的Linux有很多个版本(RedHat、Ubuntu、CentOS、SUSE等)。但这些…

linux自动化处理excel,Excel:批处理实现自动化操作(转)

Excel:批处理实现自动化操作(转)信息技术课教学过程中经常要做一些重复的工作,如建立一个班级的学生文件夹,把作业分发到学生文件夹中等等。《中国电脑教育报》2004第5期F6版《批量自动生成文件夹》一文构思巧妙,它通过VBScript来…

LINUX无法运行navixat,关于RX5700XT的驱动方法以及bug解决方案

AMD Navi显卡在macOS Catalina 10.15.1 beta2中已经正式免驱,博主购入测试,现公布新显卡的驱动方法以及bug解决方案。Windows使用DDU卸载原驱动并下载安装官方的RX5700XT的驱动即可。LinuxLinux 5.3起正式加入Navi显卡支持,所以我们要做的就是…