深入理解Java虚拟机笔记(一)----内存划分

Java内存划分

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,如下图
深入理解Java虚拟机笔记(一)----内存划分_第1张图片

一、程序计数器

程序计数器(Program Counter Register)是一块很小的内存空间,就像计算机组成原理的PC寄存器,它可以看作当前线程所执行的字节码的行号指示器,解释器通过改变计数器的值来实现分支、循环等操作。为了防止线程切换之后找不到原来执行的位置,每个线程都单独拥有一个程序计数器,可以称这类内存为“线程私有”内存。

二、Java虚拟机栈

它和程序计数器一样是线程私有的,当每个方法执行的时候Java虚拟机都会产生一个栈帧(Stack Frame),栈帧中存储了局部变量表(注:进入一个方法的时候,方法所需要的局部变量大小是确定的,不会再改变)、操作数栈、动态链接、方法出口等信息)
在Java虚拟机创建完栈帧之后就会把它入栈到虚拟机栈中,当执行完毕后就将栈帧出栈,因此当无限递归时,会创造大量的栈帧进入到虚拟机栈中,就会产生StackOverflow异常

public static  void stackLeak(){
    stackLeak();
}
public static void main(String[] args) {
    stackLeak();
}

运行结果为
深入理解Java虚拟机笔记(一)----内存划分_第2张图片
除了上述情况,当使用的Java虚拟机允许动态扩展虚拟机栈的时候,就会一直申请内存扩展虚拟机栈,直到无法申请到足够的内存,这时候便会产生OutOfMemoryError异常

三、本地方法栈

本地方法栈与虚拟机栈十分相似,虚拟机栈为Java方法提供服务,而本地虚拟机栈为本地方法服务,在栈深度溢出的时候也会产生StackOverflowError或者OutofMemoryError

四、Java堆

Java堆与虚拟机栈不同,它是所有线程共享的一片区域,它只有一个功能就是存放对象实例,我们平时使用的对象变量里面存放的则是对象地址,它指向堆中的对象实例。
一直循环生成新的对象便会造成Java堆溢出,而产生OutOfMemory异常

static class OOMObject{
}
public static void main(String[] args) {
    //使用list保持引用,防止GC回收对象
    List list= new ArrayList();
 while(true){
        list.add(new OOMObject());
 }
}

使用虚拟机参数-Xms20m -Xmx20m限制堆大小为20m不可扩展,运行上述程序后结果为
深入理解Java虚拟机笔记(一)----内存划分_第3张图片
可以看出一直产生新对象,就会占满堆内存

五、方法区

方法区与Java堆一样,也是各个线程所共享的区域,它存储了每一个类的结构信息(Class文件),例如运行时常量池,字段和方法数据,构造函数和普通方法的字节码内容,还包括一些在类,实例,接口初始化时用到的特殊方法。
当限制方法区大小并且不断加载类文件的时候,方法区就会溢出,从而产生OutOfMemory异常

你可能感兴趣的:(java,jvm)