JVM运行时内存被划分成多个区域,而除了程序计数器之外,其他几个区都会出现OutOfMemoryError异常,主要原因就是对应内存区域的内存不足以再分配内存,一般要么是内存泄漏了要么就是内存参数设置的过小而导致。本文就在实际操作中模拟下JVM内存模型中各个区域出现内存溢出的场景。

1.堆内存溢出

先设置JVM启动参数,设置初始化堆内存大小为 -Xms15M  -Xmx15M

堆内存中主要存储对象实例,所以测试堆内存溢出就需要不断的创建对象实例,并且保证这些对象实例不被垃圾回收,测试代码如下

  1. public static void main(String[] args)
  2. {
  3. heapErrorTest();
  4. }
  5.  
  6. public static void heapErrorTest()
  7. {
  8. List<User> userList = new ArrayList<>();
  9. int i = 0;
  10. try
  11. {
  12. while (true)
  13. {
  14. i++;
  15. System.out.println(i);
  16. userList.add(new User());
  17. }
  18. }
  19. catch (Exception e)
  20. {
  21. System.out.println("成功创建user对象个数为:"+i);
  22. e.printStackTrace();
  23. }
  24. }

运行结果如下示:

  1. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  2. at java.util.Arrays.copyOf(Arrays.java:3210)
  3. at java.util.Arrays.copyOf(Arrays.java:3181)
  4. at java.util.ArrayList.grow(ArrayList.java:261)
  5. at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
  6. at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
  7. at java.util.ArrayList.add(ArrayList.java:458)
  8. at com.lucky.test.jvmtest.JVMTest.heapErrorTest(JVMTest.java:27)
  9. at com.lucky.test.jvmtest.JVMTest.main(JVMTest.java:14)

此时报了OutOfMemoryError异常,也提示了是Java堆内存空间报的,但是是无法确定是什么原因导致的,也不知道具体是什么对象导致的,测试用例比较简单,而复杂的线上环境中就很难排查,所以需要让JVM在出现内存溢出的时候Dump出当前的内存堆转储快照,当出现异常后就可以使用其他工具来进行分析。针对上例,修改启动参数,添加 -XX: +HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=C:/Users/admin/Desktop/jvmdump/heapdump.hprof

运行结果为:

  1. 1 java.lang.OutOfMemoryError: Java heap space
  2. 2 Dumping heap to C:/Users/admin/Desktop/jvmdump/heapdump.hprof ...
  3. 3 Heap dump file created [24643218 bytes in 0.071 secs]
  4. 4 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  5. at java.util.Arrays.copyOf(Arrays.java:3210)
  6. at java.util.Arrays.copyOf(Arrays.java:3181)
  7. at java.util.ArrayList.grow(ArrayList.java:261)
  8. at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
  9. at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
  10. at java.util.ArrayList.add(ArrayList.java:458)
  11. at com.lucky.test.jvmtest.JVMTest.heapErrorTest(JVMTest.java:27)
  12. at com.lucky.test.jvmtest.JVMTest.main(JVMTest.java:14)

分析dump文件可以使用Eclipse的Memory Analysis插件,安装过程是打开Eclipse Help-》Eclipse Marketplace  然后搜索memory,然后直接安装即可

2.虚拟机栈内存溢出和栈溢出

虚拟机栈有栈溢出和内存溢出两种异常情况,栈溢出(StackOverFlowError)是在栈深度大于虚拟机设置的最大深度时会报出,内存溢出则会在内存不足时报出

栈溢出案例代码如下:

  1. public static void stackOverFlowErrorTest()
  2. {
  3. // 栈溢出栈的深度过长导致,可以用递归方法在模拟
  4. System.out.println("当前深度为:" + (i++));
  5. stackOverFlowErrorTest();
  6. }

运行结果为:

  1. 当前深度为:7958
  2. 当前深度为:7959
  3. 当前深度为:7960
  4. 当前深度为:7961
  5. 当前深度为:7962
  6. 当前深度为:7963
  7. Exception in thread "main" java.lang.StackOverflowError
  8. at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:449)
  9. at java.lang.StringBuilder.append(StringBuilder.java:136)
  10. at java.lang.StringBuilder.<init>(StringBuilder.java:113)
  11. at com.lucky.test.jvmtest.JVMTest.stackOverFlowErrorTest(JVMTest.java:43)
  12. at com.lucky.test.jvmtest.JVMTest.stackOverFlowErrorTest(JVMTest.java:44)
  13. at com.lucky.test.jvmtest.JVMTest.stackOverFlowErrorTest(JVMTest.java:44)

内存溢出模拟案例如下:

  1. public static void stackOutOfMemoryTest(){
  2. while(true){
  3. new Thread(new Runnable()
  4. {
  5.  
  6. @Override
  7. public void run()
  8. {
  9. dontStop();
  10. }
  11. }).start();
  12. }
  13. }
  14.  
  15. public static void dontStop(){
  16. while(true){
  17. System.out.println(Thread.currentThread().getName());
  18. }
  19. }

通过不停的创建新线程,执行一个执行不完的方法,当到达一定数量时,内存就会不足以创建新线程。

结果为:   java.lang.OutOfMemoryError: Java heap space

4.方法区内存溢出

方法区主要存放Class信息、以及静态常量,正常情况下方法区存储的内容是很少变动的,因为都是静态的内容,所以出现方法区内存溢出的情况也很少,但是有很多主流框架如Spring、Hibernate框架会对类进行增强,通过直接操作字节码,会生成大量的动态类,这时就会有大量的动态类需要存储在方法区,如果方法区的内存不足,也会出现内存溢出的情况。先设置JVM方法区内存大小 -XX:PermSize=10M -XX:MaxPermSize=10M

案例代码如下:

  1. public static void permGenErrorTest(){
  2. while(true){
  3. Enhancer enhancer = new Enhancer();
  4. enhancer.setSuperclass(User.class);
  5. enhancer.setUseCache(false);
  6. enhancer.setCallback(new MethodInterceptor()
  7. {
  8.  
  9. @Override
  10. public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3)
  11. throws Throwable
  12. {
  13. return arg3.invokeSuper(arg0, arg2);
  14. }
  15. });
  16. enhancer.create();
  17. }
  18. }

最终抛出异常:Caused by:java.lang.OutOfMemoryError:PermGen Space

JVM探秘2--详解内存溢出OutOfMemoryError异常的更多相关文章

  1. JVM探秘:MAT分析内存溢出

    本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. MAT是分析Java堆内存的一个工具,全称是 The Eclipse Memory A ...

  2. JVM类加载机制详解(二)类加载器与双亲委派模型

    在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1.通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件).而获取的方式,可 ...

  3. JVM类加载机制详解

    引言 如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 加载 在加载阶段,虚拟机需要完成以下三件事情: 1)通过一个类的全限定名来获取定义此 ...

  4. day09 详解内存管理机制

    """ 今日内容:详解内存管理 1.引用计数 在内存中为了对变量的值进行标记从而方便管理,采用引用计数的方式对变量进行标记. (1)如果变量的值被引用一次,那么该变量的引 ...

  5. JVM探秘:jmap生成内存堆转储快照

    本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. jmap 命令用来生成内存堆转储快照,一般称为heapdump或dump文件. 除了使 ...

  6. Java-异常机制详解以及开发时异常设计的原则要求

    Java-异常机制详解以及开发时异常设计的原则要求 http://blog.csdn.net/Jack__Frost/article/details/52760930?locationNum=6

  7. JVM运行原理详解

    1.JVM简析:      作为一名Java使用者,掌握JVM的体系结构也是很有必要的.      说起Java,我们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Ja ...

  8. 「JVM」知识点详解一:JVM运行原理详解

    前言 JVM 一直都是面试的必考点,大家都知道,但是要把它搞清楚又好像不是特别容易.JVM 的知识点太散,不系统,今天带大家详细的了解一下jvm的运行原理. 正文 1 什么是JVM? JVM是Java ...

  9. JVM的参数详解(转)

    12年毕业到先在处理第一年外这几年纯属于打酱油,当初自学Java然后就出来找工作了,还有第一家面试就通过了挺幸运的 但之后的这段时间一直是处于吃老本的状态.最近心情真的很不好,各种黄老邪!一直处于堕落 ...

随机推荐

  1. SpringBoot------自定义Logback日志

    帮助文档: https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-featur ...

  2. mysql的某个数据库拒绝访问的问题

    场景: mysql自带的mysql和test库都可以正常连接. 新建一个数据库demo,配置java访问时报错:Access denied for user 'root'@'localhost' (u ...

  3. bootstrap引入文件方法

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8& ...

  4. 面向对象的类关系及其C++实现

    在面向对象的程序设计中,类之间有6中关系,分别是继承, 组合, 聚合,关联, 依赖,实现,如果使用C语言实现,上面的这些关系通过"结构体包含结构体.结构体包含结构体指针以及函数指针等语法实现 ...

  5. pytest 3.9在python 2.7下的一个bug

    最在在使用pytest,用的是pytest 3.9.3,python版本为2.7.10,但一直在使用时发现总提示 File "c:\python27\Lib\json\__init__.py ...

  6. iOS - 记住用户登录状态保存用户名密码

    我们在使用APP时常用的一个功能:用户第一次进入APP时自动进入登录注册页,提示用户注册登录,用户登录成功后才进入主页,再次进入APP时,不用再次登录就直接进到主页了,就算杀掉该APP进程再次进入,依 ...

  7. web.py框架之i18n支持

    问题: 在web.py的模板文件中, 如何得到i18n的支持? Solution: 项目目录结构: proj/ |- code.py |- i18n/ |- messages.po |- en_US/ ...

  8. poj3723_Conscription

    Conscription Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12393   Accepted: 4350 Des ...

  9. laravel之路由

    laravel之路由设置 代码如下: 访问就是: 代码附上: <?php /*|--------------------------------------------------------- ...

  10. 关于js执行机制的理解

    js是单线程语言.指的是js的所以程序执行通过仅有的这一个主线程来执行. 但是还有辅助线程,包括定时器线程,ajax请求线程和事件线程. js的异步我理解的是: 主线程执行时候,从上到下依次执行,遇到 ...