JVM内存区域与内存溢出异常(深入理解JVM第二章)

1:JVM运行时数据区

JDK/JRE/JVM三者之间的关系:

JDK包含JRE,JRE包含JVM.

JDK包含JRE以及Java文件的编译和其他的工具。

JRE包含JVM以及Java运行的一些核心类库。

其中方法区和heap(堆)是线程共享的,程序计数器/虚拟机栈/本地方法栈都是线程独有的。

程序计数器

可以看作是当前线程所执行字节码的行号指示器(指向当前线程正在执行的字节码的地址)。

在任何时刻,一个处理器只能执行一条线程,因此当多个线程交替执行时,为了使线程切换后能回到指定的位置,每个线程都会有一个独立的计数器,用来判断当前线程下一条需要执行的字节码指令。

此内存区域是Java虚拟机规范中没有任何outofmemory异常情况的区域。

Java虚拟机栈

虚拟机栈也是线程所私有的,每个方法在执行的时候都会创建一个栈帧(循环调用一个方法会创建多个栈帧)。

虚拟机栈是用来存储当前线程运行方法时所需要的数据、指令、以及返回地址的数据结构,单位为栈帧。

局部变量表:用来存放编译期可知的各种基本数据类型、对象引用以及returnAddress类型。一个局部变量空间长度时32位,所以long和double类型占用两个局部变量空间。局部变量表所需要的存储空间是在编译时期确定的,当进入一个方法时这个方法所需要在帧中分配多大的空间是确定的,在方法运行期间不会发生改变的。

在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackoverflowError异常;如果虚拟机栈可与扩展,在扩展时获取不到足够的内存空间,就会抛出outofMemoryError异常。

本地方法栈

与虚拟机栈所用类似,本地方法栈服务对象是用native修饰的方法。

Java堆

JMM(java内存模型)

Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,所有的对象实例及数组都在堆上分配。

java堆中区域的分配下章

方法区

与堆一样是线程的共享区域,它用来存储被虚拟机加载的类信息、常量(1.7之后常量池放到堆里面了)、静态变量、即时编译器编译后的代码。

2:JVM的内存溢出异常

Java堆溢出

java堆用于存储对象实例,只要不断地创建对象,并且保证GC roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,当对象的数量达到堆的最大容量时,就会产生内存溢出异常。

要解决这个异常首先清楚是出现了内存泄漏还是内存溢出。

内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间。

什么意思呢?就是说,你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),而你自己出于某些原因不能再访问到那块内存(也许你把它的地址给弄丢了),这时候系统也不能再次将它分配给需要的程序。

内存溢出:就是内存不够。

内存溢出常见的原因有以下几种:

  。内存中加载的数据量过于庞大,如一次从数据库取出过多数据;

  。集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;

  。代码中存在死循环或循环产生过多重复的对象实体;

  。使用的第三方软件中的BUG;

  。启动参数内存值设定的过小

  会出现问题,自然也就有解决办法了。

  4.内存溢出的解决方案:

  第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)

  第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。

  第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。

  第四步,使用内存查看工具动态查看内存使用情况。

  其中,第三步重点排查以下几点:

  。检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

  。检查代码中是否有死循环或递归调用。

  。检查是否有大循环重复产生新对象实体。

  。检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

  。检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收

虚拟机栈和本地方法栈溢出

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

如果虚拟机在扩展栈是无法申请到足够的内存空间,将抛出OutofmemoryError。

在单线程下,如论是由于栈帧太大还是虚拟机栈容量太小,当内存无法分配时,虚拟机都会抛出StackOverflowError。

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

本机直接内存溢出

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值