Java内存区域与模拟内存区域异常

我把Java的内存区域画了一张思维导图,以及各区域的主要功能。


模拟Java堆溢出

Java堆用于存储对象实例,只要不断地创建对象并且保证GC ROOTS到对象之间有可达路径避免被回收机制清除,就可以模拟出Java堆溢出。

package hxl.insist.jvm;

import java.util.ArrayList;
import java.util.List;

/**
 * 下面是JVM Args:
 * -Xms20m 堆的最小值 -Xmx20m 堆的最小值  (设置为一样可避免堆自动扩展)
 * -XX:+HeapDumpOnOutOfMemoryError  当虚拟机出现内存溢出异常时,Dump出当前的堆转储快照
 * -XX:HeapDumpPath=E:\eclipseworkspace\UnderStandingTheJVM\hprof  设置生成的堆转储快照的路径
 * @author hanxl
 *
 */
public class HeapOutOfMemory {

    static class StuffObject {
    }

    static List<StuffObject> list = new ArrayList<StuffObject>();

    public static void main(String[] args) {

        Thread thread = new Thread(new Runnable() {
            public void run() {
                createObj();
            }
        }); 

        thread.start();

    }

    private static void createObj() {
        while (true) {
            list.add(new StuffObject());
        }
    }
}

用MemoryAnalyzer分析一下堆转储快照如下图:

从根元素到内存消耗聚集点的最短路径,可以很清楚的看到整个引用链。

在上面这张图上,我们可以清楚的看到,这个对象集合中保存了大量内部类StuffObject 对象的引用,就是它导致的内存泄露。


模拟Java虚拟机栈溢出

关于虚拟机栈,在Java虚拟机中规范了两种异常:

  1. 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
  2. 如果虚拟机地扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

模拟第一种情况:

package hxl.insist.jvm;

/**
 * 下面是JVM Args:
 * -Xss128k 设置栈容量大小
 * @author hanxl
 */
public class JavaVMStackSOF {

    public void stackLeak() {
        stackLeak();
    }

    public static void main(String[] args) throws Throwable {
        new JavaVMStackSOF().stackLeak();
    }
}

模拟第二种情况:

package hxl.insist.jvm;
/**
 * 下面是JVM Args:
 * -Xss2M 设置栈容量大小
 * @author hanxl
 */
public class JavaVMStackOOM {

    public static void main(String[] args) {
        new JavaVMStackOOM().threadInvokeMethod();
    }

    public void threadInvokeMethod() {
        while (true) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    infiniteLoop();
                }
            });
            thread.start();
        }
    }

   private void infiniteLoop() {
          while (true)
              ;
   }
}

比较两种情况为什么实现方式不同?

Java虚拟机栈是线程私有的,它的生命同期与线程相同。我们把虚拟机栈比做一个盒子,-Xss是设置盒子的大小,而一个线程只能对应一个盒子。而每个Java方法在执行的时候都会在盒子中创建一个栈帧用于存储局部变量表等一些信息。

所以为了制造出第一种情况下的异常,我们把盒子的大小设置小一点,使用递归不断调用方法,从而撑破盒子;而为了制造出第二种情况下的异常,我们应该把盒子的大小设置小大一点,多创建一些盒子,从而让其无法申请到足够的内存空间。



只要了解上面那张思维导图的内存区域,模拟出其它内存区域异常也很简单。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-25 08:52:58

Java内存区域与模拟内存区域异常的相关文章

Java内存管理以及各个内存区域详解

一.概述 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁的时间.Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如下图所示: 下面就每一个区域进行阐述. 二.运行时数据区域 程序计数器 程序计数器,可以看做是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作就是通过改变程序计数器的值来选择下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等基础功能都要依赖这个计数器来完成.

java内存结构(运行时数据区域)

java虚拟机规范规定的java虚拟机内存其实就是java虚拟机运行时数据区,其架构如下: 其中方法区和堆是由所有线程共享的数据区. Java虚拟机栈,本地方法栈和程序计数器是线程隔离的数据区. (1).程序计数器: 是一块较小的内存空间,其作用可以看作是当前线程所执行的字节码的行号指示器,字节码解析器工作时通过改变程序计数器的值来选取下一条需要执行的字节码指令.程序的分支.循环.跳转.异常处理以及线程恢复等基础功能都是依赖程序计数器来完成. Java虚拟机的多线程是通过线程轮流切换并分配处理器

Java内存管理原理及内存区域详解

一.概述 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁的时间.Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如下图所示: 下面就每一个区域进行阐述. 二.运行时数据区域 程序计数器 程序计数器,可以看做是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作就是通过改变程序计数器的值来选择下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等基础功能都要依赖这个计数器来完成.

java内存结构(执行时数据区域)

java虚拟机规范规定的java虚拟机内存事实上就是java虚拟机执行时数据区,其架构例如以下: 当中方法区和堆是由全部线程共享的数据区. Java虚拟机栈.本地方法栈和程序计数器是线程隔离的数据区. (1).程序计数器: 是一块较小的内存空间,其作用能够看作是当前线程所运行的字节码的行号指示器,字节码解析器工作时通过改变程序计数器的值来选取下一条须要运行的字节码指令. 程序的分支.循环.跳转.异常处理以及线程恢复等基础功能都是依赖程序计数器来完毕. Java虚拟机的多线程是通过线程轮流切换并分

Java基础之内存管理原理及内存区域详解

一.概述 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁的时间.Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如下图所示: 下面就每一个区域进行阐述. 二.运行时数据区域 程序计数器 程序计数器,可以看做是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作就是通过改变程序计数器的值来选择下一条需要执行的字节码指令,分支.循环.跳转.异常处理.线程恢复等基础功能都要依赖这个计数器来完成.

深入理解java虚拟机读书笔记1--java内存区域

Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随线程的开始和结束而创建和销毁. Java虚拟机所管理的内存将会包括以下几个运行时数据区域: 1 程序计数器 它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器. java虚拟机的多线程是通过轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多

Java虚拟机结构及常见内存溢出异常

每个Java虚拟机都有一个类加载器子系统,根据某个全限定名来装入类型,同样每个Java虚拟机都有一个执行引擎,它负责执行那些包含在被装载类的方法中的指令. 当虚拟机运行一个程序时,就需要从已加载的文件中得到信息,将这些信息组织到运行时数据区,以便于管理. Java运行时的数据区域划分 1.程序计数器:程序计数器是一块较小的内存空间,可以看做是当前线程的字节码的行号指示器. Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个时刻,一个处理器只会执行一条线程中的指

浅析JVM内存结构和6大区域(转)举例非常好

内存作为系统中重要的资源,对于系统稳定运行和高效运行起到了关键的作用,Java和C之类的语言不同,不需要开发人员来分配内存和回收内存,而是由JVM来管理对象内存的分配以及对象内存的回收(又称为垃圾回收.GC),这对于开发人员来说确实大大降低了编写程序的难度,但带来的一个副作用就是,当系统运行过程中出现JVM抛出的内存异常(例如OutOfMemoryError)的时候,很难知道原因是什么,另外一方面,要编写高性能的程序,通常需要借助内存来提升性能,因此如何才能合理的使用内存以及让JVM合理的进行内

java虚拟机3.运行时内存异常

在java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError异常的可能. java堆溢出 java堆用于存储对象实例,只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量达到最大堆得容量限制后就会产生内存溢出异常.当出现java堆内存溢出时,异常堆栈信息"java.lang.OutOfMemoryError"会跟着进一步提示"java heap space&qu