JVM内存划分

来源:互联网 发布:淘宝如何加入放心淘 编辑:程序博客网 时间:2024/05/01 07:31

从上图可以看出,JVM内存区域可以简单的划分为方法区,堆区,虚拟机栈,本地方法栈和程序计数器。上图中,浅色的为线程共有的内存区域,深色的为线程私有的内存区域。

可以看出,方法区和堆区是所有线程之间共享的内存区,而栈区和pc则是线程本身私有的,不能被其他线程所共享。我们简单的说下各个区域:

程序计数器:学过组成原理和操作系统的话,我们都知道其中有一个PC,用来告诉cpu运行什么指令。在JVM中,也是类似的,只不过这里的指令不是操作系统级别,而是JVM的,它可以看作当前线程所执行的字节码的行号指示器。每个线程都有一个程序计数器去执行下一个执行指令的地址。此pc不包括native方法。这是唯一一个没有内存溢出异常的内存区域。

虚拟机栈:线程私有的内存区域,其生命周期和线程自身保持一致,栈区描述的是线程内方法执行的内存模型,线程在执行方法的时候,都会创建一个栈帧,用于保存局部变量表,操作数栈,动态链接,方法出口等信息。每次的方法调用都对应着一个栈帧在虚拟机栈的入栈和出栈操作。局部变量表存放了各种编译期可知的局部变量,如基本类型和对象引用等。局部变量表的内存空间在编译期间完成内存分配,当进入一个方法时,此方法所需栈帧的局部变量大小是确定的,不会在运行期间改变。这里引用下葛一鸣书中的定义:局部变量表是栈帧的重要组成部分之一,用于保存函数的参数,函数内部的局部变量等。局部变量表中的变量只在当前函数有效,当函数的调用结束后,随着局部变量表的销毁而销毁。

    周志明书中说到,局部变量表的内存大小在编译器就已经决定了这是可以理解的,至少在编译器,我们就已经知道了函数的形参类型,方法内部的变量个数 等等,完全可以决定内存大小。

本地方法站栈:对应于native方法。

堆区:虚拟机内存中最大的一块区域。也是被所有线程共享的一块区域。此区域就是存放内存对象,几乎所有的对象实例都会在这里创建(少数在线程本地内存创建)。根据垃圾回收算法,堆区又可以细分为 新生代和老年代,其中新生代又分为Eden区和两个Survivor区。堆区上可以划分出TLAB(线程本地分配缓冲区)。

方法区:线程共享的内存区域,用于存储已经加载的类信息,常量,静态变量,即时编译后的代码数据等。JVM虚拟机规范把方法区描述为堆区的一个逻辑部分。在JDK1.6 和1.7中,方法区可以理解为Perm永久区,在JDK1.8中,永久区被彻底移除,取而代之的是元数据区,是一块堆外的直接内存。如果不指定大小,会耗尽JVM所有可用系统内存。

方法区还包含运行时常量池,用于存放运行时产生的常量。比如String.intern()方法。

直接内存:不是JVM虚拟机定义的内存区域,但也被频繁使用。比如NIO,引入了一种基于通道与缓冲区的IO方式,可以使用Native函数直接在堆外分配内存,然后通过堆中DiectByteBuffer作为这块内存的引用进行操作。

参考至周志明 葛一鸣书籍。






0 0
原创粉丝点击