Java内存分配

来源:互联网 发布:全局优化算法举例 编辑:程序博客网 时间:2024/06/06 19:13

一、运行时数据区域

java虚拟机在执行java程序的过程中会把它管理的内存划分若干个不同的数据区域。这些区域有各自的用途以及创建和销毁的时间。
运行时数据区域主要有:

  1. 程序计数器
  2. 虚拟机栈
  3. 本地方法栈
  4. 方法区

1. 程序计数器

功能:指示当前执行的字节码地址,可以看做当前线程执行的字节码的行号指示器。
java多线程中,任何一个确定时刻,一个处理器都会只执行一条程序指令。为了线程切换后能恢复正确位置,每条线程都需要有一个独立的程序计数器,各条线程之间互不影响,独立存储,称为线程私有内存
注意:如果一个程序执行的是一个java方法,这个计数器指示的就是正在执行的虚拟机字节码地址;如果执行的是Native方法,这个计数器的值为空。此内存区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况区域

2. java虚拟机栈

java虚拟机栈是线程私有的,生命周期和线程相同。

java方法执行的内存模型

虚拟机栈描述的是java方法执行的内存模型:每个方法在执行时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机中出入栈的过程。

局部变量表

局部变量表存放了编译时期可知的各种基本数据类型、对象引用和returnAddress(指向一条字节码指令地址)。
局部变量表所需的内存空间在编译时期完成分配,当进入一个方法时,这个方法在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表大小。

异常

这个区域规定了两个异常
- StackOverflowError异常:线程请求的栈的深度大于虚拟机所允许的深度
- OutOfMemoryError异常:如果虚拟机栈可以动态扩展,当扩展时无法申请到足够内存,就会出现此异常。

3 本地方法栈

与虚拟机栈十分相似,区别是:虚拟机栈为虚拟执行java方法提供服务,本地方法栈则为虚拟机使用到的Native方法服务。
有的虚拟机把本定方法栈和虚拟机栈合二为一(如HotSpot虚拟机)。

4. java堆

java堆是java虚拟机所管理的内存中最大的一块,而且是所有线程共享的内存区域。此区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。但是随着JIT编译器的发展和逃逸分析技术成熟,栈上分配、标量替换优化技术将会使堆上分配内存不那么绝对。

异常

java堆既可以实现为固定大小的,也可以实现为可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的。
如果堆中没有内存完成实例分配时,并且也无法扩展时,将会抛出OutOfMemoryError

5. 方法区

可以固定大小或者可扩展,是一个线程共享的内存区域,用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

运行时常量池

这个区域是方法区的一部分。
常量池用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

比如类名,接口名,方法名等对应的内存地址

异常

无法满足内存分配时,就会抛出OutOfMemoryError

二、直接内存区

直接内存区不属于java虚拟机运行时数据区的一部分,也不是java虚拟机规范中规定义的内存区域。
在java1.4中加入NIO类,引入了一种基于通道与缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的应用进行操作。这样在一些场合可以显著提升性能,因为避免了在java堆和Native堆上来回复制数据。

异常

内存肯定会收到本机物理内存限制,所以这块内存也会触发OutOfMemoryError