学习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. [jvm][面试]JVM 调优总结

    https://blog.csdn.net/wfh6732/article/details/57422967 堆大小设置JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-b ...

  2. 【PMP】项目生命周期和开发生命周期

    一.定义 项目生命周期:指项目从启动到完成所经历的一系列阶段. 开发生命周期:项目生命周期内通常有一个或多个阶段与产品.服务或成果的开发相关,这些阶段称为开发生命周期. 二.生命周期 预测型生命周期( ...

  3. [转]PID控制算法原理

    PID控制算法是工业界使用极其广泛的一个负反馈算法,相信这个算法在做系统软件时也有用武之处,这里摘录了知乎上的一篇文章,后面学习更多后自己总结一篇 以下为原文: PID控制应该算是应用非常广泛的控制算 ...

  4. 像Excel一样使用python进行数据分析

    Excel是数据分析中最常用的工具,本篇文章通过python与excel的功能对比介绍如何使用python通过函数式编程完成excel中的数据处理及分析工作.在Python中pandas库用于数据处理 ...

  5. [druid]大数据挑战——如何使用Druid实现数据聚合

    -- 知道你为什么惧组件很多的一些开源软件? 因为缺乏阅读能力. 最近我接手了druid+kafka+elk一套等日志系统. 但是我对druid很陌生, 周旋了几天, 官网文档快速开始照着做了下. 看 ...

  6. [HDFS Manual] CH7 ViewFS Guide

    ViewFS Guide ViewFS Guide 1 介绍 2. The Old World(Prior to Federation) 2.1单个Namenode Clusters 2.2 路径使用 ...

  7. 5个最好用AngularJS构建应用程序框架

    如果你打算建立自己的Web应用与AngularJS,那么现在是时候开始了.如果这个想法吓到你了,删除所有的恐慌,从你的头脑中有一些框架,AngularJS提供方便的支持.有一些预先的框架,使用框架可以 ...

  8. LaTeX数学模式&上下标&代码块

    效果就是如上图所示了.学习了使用数学模式插入公式和使用上标和公式的编号.这里的目录没有展开,在编译一次目录会展开,代码块会被挤到下一页上面去. \documentclass[UTF8]{ctexart ...

  9. 关于Retrofit网络请求URL中含有可变参数的处理

    开题:在此默认各位看官对Retrofit.以及Okhttp已经有过一定的了解及应用,所以今天我们不谈基础入门的东西,今天我们谈在Retrofit请求接口管理类中URL参数含有动态参数的处理方式.一般我 ...

  10. Vue .Net 前后端分离框架搭建

    [参考]IntellIJ IDEA 配置 Vue 支持 打开Vue项目 一.前端开发环境搭建 1.零基础 Vue 开发环境搭建 打开运行Vue项目 2.nodejs http-proxy-middle ...