1.前言

上一篇我们介绍了java的内存区域结构,这一篇,模拟内存溢出的几个场景,下面一个图是总体的指导思想:

2.Java堆溢出

Java堆唯一的作用就是存储对象实例,只要保证不断创建对象并且对象不被回收,那么对象数量达到最大堆容量限制后就会产生内存溢出异常了。所以测试的时候把堆的大小固定住并且让堆不可扩展即可。测试代码如下:

 1 package com.xrq.test;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 /**
7 * 测试内容:堆溢出
8 *
9 * 虚拟机参数:-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
10 */
11 public class HeapOverflowTest
12 {
13 public static void main(String[] args)
14 {
15 List<HeapOverflowTest> list = new ArrayList<HeapOverflowTest>();
16 while (true)
17 {
18 list.add(new HeapOverflowTest());
19 }
20 }
21 }

运行结果

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid8876.hprof ...
Heap dump file created [15782068 bytes in 0.217 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2760)
at java.util.Arrays.copyOf(Arrays.java:2734)
at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
at java.util.ArrayList.add(ArrayList.java:351)
at com.xrq.test.HeapOverflowTest.main(HeapOverflowTest.java:18)

这种异常很常见,也很好发现,因为都提示了“Java heap space”了,定位问题的话,根据异常堆栈分析就好了,行号都有指示。

解决方案:可以调大堆的大小或者从代码上检视是否存在某些对象生命周期过长、持有状态时间过长的情况,长时间减少程序运行期间的内存消耗。

另外,由于Java堆内也可能发生内存泄露(Memory Leak),这里简要说明一下内存泄露和内存溢出的区别:

内存泄露:是指分配出去的内存没有被回收回来,由于失去了对该内存区域的控制,因而造成了资源的浪费。Java中一般不会产生内存泄露,因为有垃圾回收器自动回收垃圾,但这也不绝对,当我们new了对象,并保存了其引用,但是后面一直没用它,而垃圾回收器又不会去回收它,这边会造成内存泄露,

内存溢出:是指程序所需要的内存超出了系统所能分配的内存(包括动态扩展)的上限。

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

运行时常量池也是方法区的一部分,所以这两个区域一起看就可以了。这个区域的OutOfMemoryError可以利用String.intern()方法来产生。这是一个Native方法,意思是如果常量池中有一个String对象的字符串就返回池中的这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中去,并且返回此String对象的引用。测试代码如下:

 1 package com.xrq.test;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 /**
7 * 测试内容:常量池溢出(这个例子也可以说明运行时常量池为方法区的一部分)
8 *
9 * 虚拟机参数-XX:PermSize=10M -XX:MaxPermSize=10M
10 */
11 public class ConstantPoolOverflowTest
12 {
13 public static void main(String[] args)
14 {
15 List<String> list = new ArrayList<String>();
16 int i = 0;
17 while (true)
18 {
19 list.add(String.valueOf(i++).intern());
20 }
21 }
22 }

运行结果

Exception in thread "Reference Handler" Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at com.xrq.test.ConstantPoolOverflowTest.main(ConstantPoolOverflowTest.java:19)
java.lang.OutOfMemoryError: PermGen space
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:123)

之前有讲过,对于HotSpot而言,方法区=永久代,这里看到OutOfMemoryError的区域是“PermGen space”,即永久代,那其实也就是方法区溢出了。注意一下JDK1.7下是不会有这个异常的,while循环将一直下去,因为JDK1.7之后溢出了永久代并采用Native Memory来实现方法区的规划了

4.栈溢出

Java虚拟机规范中描述了如果线程请求的栈深度太深(换句话说方法调用的深度太深),就会产生栈溢出了。那么,我们只要写一个无限调用自己的方法,自然就会出现方法调用的深度太深的场景了。测试代码如下

 1 package com.xrq.test;
2
3 /**
4 * 测试内容:栈溢出测试(递归调用导致栈深度不断增加)
5 *
6 * 虚拟机参数:-Xss128k
7 */
8 public class StackOverflowTest
9 {
10 private int stackLength = 1;
11
12 public void stackLeak()
13 {
14 stackLength++;
15 stackLeak();
16 }
17
18 public static void main(String[] args) throws Throwable
19 {
20 StackOverflowTest stackOverflow = new StackOverflowTest();
21 try
22 {
23 stackOverflow.stackLeak();
24 }
25 catch (Throwable e)
26 {
27 System.out.println("stack length:" + stackOverflow.stackLength);
28 throw e;
29 }
30 }
31 }

运行结果:

stack length:1006
Exception in thread "main" java.lang.StackOverflowError
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:14)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
  ...

多线程:这里需要注意一下多线程的情况,多线程下通过不断创建线程的方式,可以产生OutOfMemoryError异常,因为每个线程都有自己的栈空间,栈空间越大,越容易产生内存溢出异常。其实这也很好理解,操作系统分配给进程的内存是有限制的,比如32位的Windows限制为2GB。虚拟机提供了了参数来控制Java堆和方法区这两部分内存的最大值,剩余内存为2GB-最大堆容量-最大方法区容量,程序计数器很小就忽略了,虚拟机进程本身的耗费也不算,剩下的内存就是栈的了。每个线程分配到的栈容量越大,可建立的线程数自然就越少,建立线程时就越容易把剩下的内存耗尽,可能造成操作系统的假死。

多线程导致的OutOfMemoryError,在不能减少线程数的情况下,就只能通过减少最大堆和每个线程的栈容量来换取更多的线程了。

单线程:StackOverFlowError这个异常,有错误堆栈可以阅读,比较好定位。而且如果使用虚拟机默认参数,栈深度在大多数情况下,达到1000~2000完全没有问题,正常方法的调用这个深度应该是完全够了。

转载地址:http://www.cnblogs.com/xrq730/p/4833713.html

http://blog.csdn.net/ns_code/article/details/17565503

Java虚拟机3:内存溢出的更多相关文章

  1. 深入理解java虚拟机【内存溢出实例】

    通过简单的小例子程序,演示java虚拟机各部分内存溢出情况: (1).java堆溢出: Java堆用于存储实例对象,只要不断创建对象,并且保证GC Roots到对象之间有引用的可达,避免垃圾收集器回收 ...

  2. 如何写出让java虚拟机发生内存溢出异常OutOfMemoryError的代码

    程序小白在写代码的过程中,经常会不经意间写出发生内存溢出异常的代码.很多时候这类异常如何产生的都傻傻弄不清楚,如果能故意写出让jvm发生内存溢出的代码,有时候看来也并非一件容易的事.最近通过学习< ...

  3. java虚拟机涉及内存溢出

    Java语言写的代码是.java文件,它会被特定程序编译(javac.exe,它会被Eclipse之类的IDE调用)成字节码(bytecode),字节码不能直接在CPU上运行,需要另一个程序读取并执行 ...

  4. Java 虚拟机的内存溢出

    在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError 异常的可能. 在Eclipse中进行JVM参数设置 可以直接通过上方菜单栏的 ...

  5. java虚拟机(四)--内存溢出、内存泄漏、SOF

    学习了java运行时数据区,知道每个内存区域保存什么数据,可以参考:https://www.cnblogs.com/huigelaile/p/diamondshine.html,然后了 解内存溢出和内 ...

  6. 【java虚拟机】内存溢出与内存泄漏

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/7354857.html 一.基本概念 内存溢出:简单地说内存溢出就是指程序运行过程中申请的内存大于系统能够提 ...

  7. 【java虚拟机】内存溢出解决思路

    转自:https://blog.csdn.net/u013521220/article/details/79523633 内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的程序异常,总是可以知 ...

  8. (一)深入java虚拟机之内存溢出与分析

    一.内存溢出程序 public class Test { public static void main(String[] args) { List<User> userList=new ...

  9. 实战Java虚拟机之一“堆溢出处理”

    从今天开始,我会发5个关于java虚拟机的小系列: 实战Java虚拟机之一“堆溢出处理” 实战Java虚拟机之二“虚拟机的工作模式” 实战Java虚拟机之三“G1的新生代GC” 实战Java虚拟机之四 ...

  10. 从Java虚拟机的内存区域、垃圾收集器及内存分配原则谈Java的内存回收机制

    一.引言: 在Java中我们只需要轻轻地new一下,就可以为实例化一个类,并分配对应的内存空间,而后似乎我们也可以不用去管它,Java自带垃圾回收器,到了对象死亡的时候垃圾回收器就会将死亡对象的内存回 ...

随机推荐

  1. Linux 线程实现机制分析--转

    http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 一.基础知识:线程和进程 按照教科书上的定义,进程是资源管理的最小单位,线程是程 ...

  2. 记一个bug的排查过程---复盘

    公众号做了新需求:菜单的click事件,支持多条客服消息. 上线后,只有一个功能不好使,是点击菜单,预期发一条文本类型的客服消息. 实际操作时,点这个菜单项后,什么也没有发生. elk上看日志,也没有 ...

  3. AngularJS的日期格式化有两种形式

    AngularJS的日期格式化有两种形式,一种是在HTML页面,一种是在JS代码里,都是用到AngularJS的过滤器$filter. HTML: date_expression 即 你在$scope ...

  4. AngularJS中的动画实现

    AngularJS 动画 AngularJS 提供了动画效果,可以配合 CSS 使用. AngularJS 使用动画需要引入 angular-animate.min.js 库. <script ...

  5. Swift构造器链

    IDE:Xcode Version7.3.1 指定构造器: 1>名字为init的方法前没有前缀(子类重写时有override除外), 2>一个类中至少有一个指定构造器,其必须初始化类中的所 ...

  6. java 记录

    1.spring ide 的安装图解 https://blog.csdn.net/u012369373/article/details/55097380 2.ssm框架配置内容 http://www. ...

  7. FFmpeg的tutorial 学习

    一.前言: 这是一个学习 FFmpeg 的 tutorial 系列. 这个是一个对初学者比较友好的FFmpeg学习教程,作者一步步引导我们实现了一个音视频同步的播放器. 参考链接: 原文地址: htt ...

  8. lincode 题目记录5

    Course Schedule 安排课表   Frog Jump  最长回文字符串长度 Course Schedule 选课方案问题,题目说的很清楚了就是bfs或者dfs,然后加个字典优化,弄了好久没 ...

  9. cssText用法和使用说明

    cssText 本质是什么? cssText 的本质就是设置 HTML 元素的 style 属性值. cssText 怎么用? document.getElementById("d1&quo ...

  10. curl POST JSON

    1. 场景 Controller接收json格式数据 封装bean @RequestMapping(value = "/bb", method = RequestMethod.PO ...