学习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. Vue $emit()不触发方法的原因

    vue使用$emit时,父组件无法触发监听事件的原因是: $emit传入的事件名称只能使用小写,不能使用大写的驼峰规则命名

  2. HighLight.js 使用Demo

    复制下面代码,保存为html,浏览器打开预览即可. <!DOCTYPE html> <html> <head> <meta charset="utf ...

  3. Mybatis抛出:Cannot obtain primary key information from the database, generated objects may be incomplete

    使用 mybatis generator 生成pojo.dao.mapper时,可能会遇到 Cannot obtain primary key information from the databas ...

  4. 关于asyncio知识(二)

    一.asyncio之—-入门初探 通过上一篇关于asyncio的整体介绍,看过之后基本对asyncio就有一个基本认识,如果是感兴趣的小伙伴相信也会尝试写一些小代码尝试用了,那么这篇文章会通过一个简单 ...

  5. Atitit r2017 r6 doc list on home ntpc.docx

    Atitit r2017 r6 doc list on home ntpc.docx 驱动器 D 中的卷是 p2soft 卷的序列号是 9AD0-D3C8 D:\ati\r2017 v4 raf\r2 ...

  6. ownCloud安卓android客户端版本2.9.3

    2018年11月26日 版本升级:ownCloud 2.9.3. 下载地址 2018年7月28日 版本升级:ownCloud 2.8.0,支持指纹.图案登录APP. 2018年2月6日 版本升级:ow ...

  7. seaJS简介和完整实例

    什么是 seaJS ? 和requireJS相似的,seaJS 也是用JavaScript编写的JS框架,主要功能是可以按不同的先后依赖关系对 JavaScript 等文件的进行加载工作,可简单理解为 ...

  8. Asp.Net百度站长工具的主动推送功能

    public static string PostUrl(string[] urls) { try { string formUrl = "http://data.zz.baidu.com/ ...

  9. ffmpeg转码器移植VC的project:ffmpeg for MFC

    本文介绍一个自己做的FFMPEG移植到VC下的开源project:ffmpeg for MFC.本project将ffmpegproject中的ffmpeg转码器(ffmpeg.c)移植到了VC环境下 ...

  10. centos7修改系统时间、时区

    直接用下面命令直接更换时区 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime