学习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. Device does not seem to be present [常见错误解决]

    一.故障现象: [root@c1node01 ~]# service network restart Shutting down loopback insterface:                ...

  2. SELECT INTO和INSERT INTO SELECT的区别 类似aaa?a=1&b=2&c=3&d=4,如何将问号以后的数据变为键值对 C# 获取一定区间的随即数 0、1两个值除随机数以外的取值方法(0、1两个值被取值的概率相等) C# MD5 加密,解密 C#中DataTable删除多条数据

    SELECT INTO和INSERT INTO SELECT的区别   数据库中的数据复制备份 SELECT INTO: 形式: SELECT value1,value2,value3 INTO Ta ...

  3. Gradle 打可执行jar包

    初次使用Gradle,想和maven一样,把gradle项目打成可执行jar包,具体步骤: 1.下载gradle 版本,并配置环境变量, 下载地址:https://gradle.org/release ...

  4. Kubernetes 1.12公布:Kubelet TLS Bootstrap与Azure虚拟机规模集(VMSS)迎来通用版本号

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/M2l0ZgSsVc7r69eFdTj/article/details/82880341 https: ...

  5. sshpass 实现shell脚本直接加载密登录服务器

    主要命令:sshpass 这个命不是系统自带的,需要安装: # which sshpass/usr/bin/sshpass[root@666 tools]# rpm -qf /usr/bin/sshp ...

  6. 斐讯K1 K2 开启Telnet

    官方V21.4.5.5前的ROM,直接打开下边这个链接就直接开telnet了,然后就可以随便搞了 http://192.168.2.1/goform/gra_NTPSyncWithLocal?text ...

  7. spring boot 项目启动无任何反应

    遇到的问题 spring boot项目启动后无任何报错,ps有进程,nohub无日志 定位 更换jar包,问题依然存在,将jar包放到其他服务器,运行正常,排除打包问题 同服务器其他系统运行正常,但停 ...

  8. 02Hadoop二次排序2

    案例: 数据: 邮编   |     日期     |金额 ILMN,2013-12-05,97.65GOOD,2013-12-09,1078.14IBM,2013-12-09,177.46ILMN, ...

  9. [原创]Fashion汽车定位器拆解

    随着共享单车的爆发增长,定位方案被彻底激活.当下主流的共享单车都采用了MTK2503的方案(后续再详细分解),本文针对某商城热卖的汽车定位器进行拆解分析. 第一部分,定位器外观. 第二部分,拆解开壳, ...

  10. [转java发送http的get、post请求]

    Http请求类 package wzh.Http; import java.io.BufferedReader; import java.io.IOException; import java.io. ...