学习jvm时看到几篇非常好的系列文章,转载了:

http://my.oschina.net/linuxfelix/blog/128406

一、概要

我们可以带着以下几个问题去学习自动内存管理机制,罗列如下:

  1. 什么操作可能导致内存溢出?
  2. 有哪些种类的内存溢出?
  3. 都是在内存的哪些区域溢出?
 

二、运行时数据区域

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,如下图所示

其中虚拟机栈、本地方法栈和程序技术器是线程私有的,方法区和堆是线程共享的.

2.1程序计数器

作用:当前线程所执行的字节码的行号指示器

  • 字节码解释器工作时通过改变它的值来选取下一条需要执行的字节码指令
  • 分支、循环、跳转、异常处理和线程恢复都依赖于它

2.2虚拟机栈

栈的作用:栈用于存储局部变量表、操作数栈、动态链接和方法出口等信息.

其中局部变量表用于存放8种基本数据类型(boolean,byte,char,short,int,float,long,double)和reference类型.

reference类型:

  • 指向对象起始地址的引用指针

  • 指向一个代表对象的句柄

  • 指向一条字节码指令的地址

可抛出两种异常状况

  • 线程请求的栈深度大于虚拟机所允许的栈深度,抛出StackOverflowError异常

  • 当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常是

2.3本地方法栈

与虚拟机栈的作用非常相似.其区别是虚拟机栈执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务

同时也会抛出StackOverflowError和OutOfMemoryError异常

2.4堆

堆的作用:分配所有的对象实例和数组。可以抛出OutOfMemoryError异常。

2.5方法区

方法区的作用:用于存储已被虚拟机加载的类信息(Class)、常量(final修饰)、静态变量(static)和即时编译器编译后的代码(code)

可以抛出OutOfMemoryError异常

2.6运行时常量池

属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用(在以后介绍Class结构会讲到),在类加载后存放到方法区的运行时常量池中。可抛出OutOfMemoryError异常

三、对象访问

主流的两种访问方式:使用句柄和直接指针。(HotSpot虚拟机就是使用直接指针的访问方式)

使用句柄访问

使用直接指针访问
优缺点比较
 

四、OutOfMemoryError异常

在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError异常的可能.

下面通过若干实例来验证异常发生的场景.以下代码的开头都注释了执行时所需要设置的虚拟机启动参数,这些参数对实验结果有直接影响,请调试代码的时候不要忽略掉.

4.1Java堆溢出

堆里放的是new出来的对象,所以这部分很简单不断的new对象就可以了,但是为了防止对象new出来之后被GC,所以把对象new出来的对象放到一个List中去即可。为了有更好的效果,可以在运行前,调整堆的参数。

  1.  
    import java.util.ArrayList;
  2.  
    import java.util.List;
  3.  
    /**
  4.  
    * VM Args: -Xms20m -Xms20m - XX:+HeapDumpOnOutOfMemoryError
  5.  
    * @author Administrator
  6.  
    *
  7.  
    */
  8.  
    public class HeapOOM {
  9.  
    static class OOMObject{}
  10.  
    public static void main(String[] args) {
  11.  
    List<OOMObject> list = new ArrayList<HeapOOM.OOMObject>();
  12.  
    while(true ){
  13.  
    list.add( new OOMObject());
  14.  
    }
  15.  
    }
  16.  
    }

运行结果

4.2虚拟机栈溢出

  • 在单线程的堆中我们不断的让一个成员变量自增,容纳这个变量的单元无法承受这个变量了,就抛出StackOverflowError了。
  • 可以开尽量多的线程,并在每个线程里调用native的方法,就自然会抛出 OutOfMemoryError了。
  1.  
    /**
  2.  
    * VM Args: - Xss64k
  3.  
    * @author Administrator
  4.  
    *
  5.  
    */
  6.  
    public class JavaVMStackSOF {
  7.  
    private int stackLength = 1;
  8.  
    public void stackLeak(){
  9.  
    stackLength ++;
  10.  
    stackLeak();
  11.  
    }
  12.  
    public static void main(String[] args) throws Throwable {
  13.  
    JavaVMStackSOF oom = new JavaVMStackSOF();
  14.  
    try{
  15.  
    oom.stackLeak();
  16.  
    } catch(Throwable e){
  17.  
    System. out.println("Stack length:" + oom.stackLength);
  18.  
    throw e;
  19.  
    }
  20.  
    }
  21.  
    }

运行结果

 

4.3 方法区溢出

可采用增强Class加载的方式。基本思路是运行时产生大量的类去填满方法区,直到溢出。
借助第三方类库CGLib 直接操作字节码运行,生成大量的动态类。
  1.  
    import java.lang.reflect.Method;
  2.  
    import net.sf.cglib.proxy.MethodInterceptor;
  3.  
    import net.sf.cglib.proxy.Enhancer;
  4.  
    import net.sf.cglib.proxy.MethodProxy;
  5.  
    /**
  6.  
    * VM Args:- XX:PermSize=10m -XX:MaxPermSize=10m
  7.  
    * @author Administrator
  8.  
    *
  9.  
    */
  10.  
    public class JavaMethodAreaOOM {
  11.  
    public static void main(String[] args) {
  12.  
    while (true ){
  13.  
    Enhancer enhancer = new Enhancer();
  14.  
    enhancer.setSuperclass(OOMObject. class );
  15.  
    enhancer.setUseCache( false );
  16.  
    enhancer.setCallback( new MethodInterceptor() {
  17.  
    @Override
  18.  
    public Object intercept(Object obj, Method method, Object[] args,
  19.  
    MethodProxy proxy) throws Throwable {
  20.  
    return proxy.invoke(obj, args);
  21.  
    }
  22.  
    });
  23.  
    enhancer.create();
  24.  
    }
  25.  
    }
  26.  
    static class OOMObject{
  27.  
     
  28.  
    }
  29.  
    }
运行结果
java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
... 8 more

4.4 运行时常量池溢出

可采用String类的intern方法。
  1.  
    import java.util.ArrayList;
  2.  
    import java.util.List;
  3.  
    /**
  4.  
    * VM Args:- XX:PermSize=10m -XX:MaxPermSize=10m
  5.  
    * @author Administrator
  6.  
    *
  7.  
    */
  8.  
    public class RuntimeConstantPoolOOM {
  9.  
    public static void main(String[] args) {
  10.  
    List<String> list = new ArrayList<String>();
  11.  
    int i = 0;
  12.  
    while (true ){
  13.  
    list.add(String. valueOf(i++).intern());
  14.  
    }
  15.  
    }
  16.  
    }
运行结果
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
      at java.lang.String.intern(   Native Method  )
      at RuntimeConstantPoolOOM.main(   RuntimeConstantPoolOOM.java:14   )

相关引用:

http://my.oschina.net/linuxfelix/blog/128406      《深入理解Java虚拟机》学习小记一之自动内存管理机制(一)

JVM—内存溢出、OutOfMemoryError、StackOverflowError的更多相关文章

  1. JVM内存溢出分析java.lang.OutOfMemoryError: Java heap space

    JVM内存溢出查询java.lang.OutOfMemoryError: Java heap space查出具体原因分为几个预备步骤 1.在运行java程序是必须设置jvm -XX:+HeapDump ...

  2. jvm内存溢出分析

    概述 jvm中除了程序计数器,其他的区域都有可能会发生内存溢出 内存溢出是什么? 当程序需要申请内存的时候,由于没有足够的内存,此时就会抛出OutOfMemoryError,这就是内存溢出 内存溢出和 ...

  3. jvm内存溢出问题

     Java内存溢出详解 一.常见的Java内存溢出有以下三种: 1. java.lang.OutOfMemoryError: Java heap space ----JVM Heap(堆)溢出 J ...

  4. jvm 内存溢出问题排查方法

    如果你做TCP通讯或者map集合操作,并发处理等功能时,很容易出现 Java 内存溢出的问题.本篇文章,带领大家深入jvm,分析并找出jvm内存溢出的代码. jvm中除了程序计数器,其他的区域都有可能 ...

  5. JVM 内存溢出详解(栈溢出,堆溢出,持久代溢出、无法创建本地线程)

    出处:  http://www.jianshu.com/p/cd705f88cf2a 1.内存溢出和内存泄漏的区别 内存溢出 (Out Of Memory):是指程序在申请内存时,没有足够的内存空间供 ...

  6. JVM 内存溢出 实战 (史上最全)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  7. Tomcat中JVM内存溢出及合理配置及maxThreads如何配置(转)

    来源:http://www.tot.name/html/20150530/20150530102930.htm Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚 ...

  8. Tomcat中JVM内存溢出及合理配置

    Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对Java JVM有关内存方面的知识 ...

  9. JVM内存溢出及合理配置

    Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对Java JVM有关内存方面的知识 ...

  10. 巧解Tomcat中JVM内存溢出问题

    你对Tomcat 的JVM内存溢出问题的解决方法是否了解,这里和大家分享一下,相信本文介绍一定会让你有所收获. tomcat 的JVM内存溢出问题的解决 最近在熟悉一个开发了有几年的项目,需要把数据库 ...

随机推荐

  1. 安装了 R2 Integration Servic 之后,SQL Server 2008 Management Studio报错

    问题产生 IM数据库服务器未安装Integration Servic,影响备份.在安装了安装了 SQL Server 2008 R2 Integration Servic 之后,SQL Server ...

  2. 树莓派进阶之路 (037) - 设置树莓派3 B+的静态IP

    修改/etc/dhcpcd.conf 文件 sudo vim /etc/dhcpcd.conf interface eth0 static ip_address= static routers=192 ...

  3. [转]Redis内部数据结构详解-sds

    本文是<Redis内部数据结构详解>系列的第二篇,讲述Redis中使用最多的一个基础数据结构:sds. 不管在哪门编程语言当中,字符串都几乎是使用最多的数据结构.sds正是在Redis中被 ...

  4. 从yield 到yield from再到python协程

    yield 关键字 def fib(): a, b = 0, 1 while 1: yield b a, b = b, a+b yield 是在:PEP 255 -- Simple Generator ...

  5. centos6 利用外部的smpt服务器计划任务发送邮件

    centos可通过修改配置文件以使用外部SMTP服务器,达到不使用sendmail而用外部的smtp服务器发送邮件的目的, 操作如下: 一.安装mailx与sendmail # yum -y inst ...

  6. java 查看SOAP请求报文

    log.info("ESB 请求URL = " + cachedEndpoint.toString());//打印SOAP请求报文 add by LinJC on 20170120 ...

  7. Xshell Plus

    https://xshell.woytu.com 一个在线生成Xshell Plus 等软件的注册码的网址: https://xshell.spppx.org/

  8. tf更新tensor/自定义层

    修改Tensor特定位置的值 如 stack overflow 中提到的方案. TensorFlow不让你直接单独改指定位置的值,但是留了个歪门儿,就是tf.scatter_update这个方法,它可 ...

  9. 用反卷积(Deconvnet)可视化理解卷积神经网络还有使用tensorboard

    『cs231n』卷积神经网络的可视化与进一步理解 深度学习小白——卷积神经网络可视化(二) TensorBoard--TensorFlow可视化 原文地址:http://blog.csdn.net/h ...

  10. bash python获取文本中每个字符出现的次数

    bash: grep -o . myfile | sort |uniq -c python:  使用collections模块 import pprint import collections f = ...