jvm学习记录 -- Java内存区域与内存溢出异常

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Czymessi/article/details/52277363

说明:主要参照 《深入理解Java虚拟机--JVM高级特性与最佳实践》一书,以作记录学习的过程。

一:概述

           对于C和C++程序员来说,拥有着对每个对象的的“所有权”,而Java则是通过虚拟机来自动管理内存;所以一旦Java虚拟机出现内存泄漏和溢出方面的问题时,如果不了解虚拟机怎样使用内存,那么排查错误将会成为一项异常艰难的工作。

二:运行时数据区域

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

           

各个区域都有各自的用途,以及创建和销毁时间。

   1.程序计数器:一块较小的内存空间,是当前线程所执行的字节码的行号指示器。为了在多线程环境下,线程切换后能恢复到正确的执行位置,所以每条线程都需要有一个独 

立的程序计数器。

   2.Java虚拟机栈:线程私有,生命周期与线程相同;

 虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

该部分规定了两种异常状况(测试代码如下):StackOverflowError(线程请求的栈深度大于虚拟机所允许的深度);

 OutOfMemoryError(如果虚拟机栈可动态扩展,在扩展时无法申请到足够的内存时)

                                    

public static void main(String[] args) {
    //该句会出现java.lang.StackOverflowError 异常
    testStackOverflowError();

    //以下代码会出现java.lang.OutOfMemoryError 异常
    List list = new ArrayList();
    for (;;) {
        int[] temp = new int[1000000];
        list.add(temp);
    }

}
public static void testStackOverflowError(){
    for (;;){
        testStackOverflowError();
    }
}

  3.本地方法栈:与虚拟机栈作用相似。

  4.Java堆:被所有线程共享的一个区域,也是Java虚拟机所管理的的内存中最大的一块,该区域唯一的目的就是存放对象实例。

还可以细分为:新生代和老年代;再细分可分为Eden空间、From Survivor空间、To Survivor空间(分代收集算法)。

如果堆中没有内存完成实例分配,且无法再扩展时,将会抛出OutOfMemoryError异常。

  5.方法区:同Java堆一样是线程共享的内存区域,用于存储已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。(虽然Java虚拟机规范将方法区描述为堆的一个逻辑部分,但它却有一个别名:Non-Heap,即非堆);

当方法区无法满足内存分配需求时,将抛出OutOfMemoryError。


没有更多推荐了,返回首页