Java虚拟机笔记-内存区与内存溢出

java 5 2016-02-29 13:03
女装

Java的内存区域

Java虚拟机在执行Java程序中会把它所管理的内存划分为若干个数据区域,这些区域有各自的用途,以及生命周期,有些依赖虚拟机进程启动而存在,有些依赖用户线程的启动和结束而建立和销毁

运行时内存

程序计数器(Program Counter Register)

程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。
由于Java虚拟机的多线程是通过线程调度(轮询)切换分配处理器执行时间的方式来实现的,在任何一个确定的时刻都只会执行一条线程中的指令。所以为了当线程切换后能找到之前执行指令的位置,每个线程都需要有一个独立的程序计数器,各个线程之间的程序计数器互相不影响,这类内存区域为“线程私有”的内存区域。

Java虚拟机栈(Java Virtual Machine Stack)

Java虚拟机栈和程序计数器一样,Java虚拟机栈(以下简称栈)也是“线程私有”的,它的生命周期和线程相同,每个方法在执行时都会创建一个栈帧(Stack Frame)用于存储局部变量表(方法中定义的变量),操作数栈,动态链接,方法出口等信息。每个方法从调用直至执行完成的过程,就是对应着一个栈帧在栈中入栈和出栈的过程。

本地方法栈

本地方法栈和Java虚拟机栈一样,本地方法栈用于执行Native方法

Java堆(Java Heap)

Java堆是被所有线程共享的一块内存区域,在虚拟机启动时被创建。此内存区域的唯一目的就是存放对象的实例,几乎所有的对象实例都在这里分配内存,Java堆是垃圾收集器管理的主要区域,由于现在很多收集器都采用分代收集算法,所有Java堆还可以细分为:新生代和老年代。可以通过-Xmx和-Xms来控制堆内存的大小

方法区

方法区和Java堆一样,也是各个线程共享的内存区域,它用于存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。一般也称作为“永代区”(Permanent Generation),这里要特别说明一下,因为我们使用的主流虚拟机HotSpot的设计团队用“永代区”来实现方法区,这样HotSpot的垃圾收集器就可以像管理堆那样管理这部分内存,在JDK1.7的HotSpot中,已经把字符串常量池移出“永代区”了。

直接内存(Direct Memory)

直接内存并不是虚拟机运行时数据区的一部分,但是如果你使用了NIO的类,就会导致OutOfMemoryError异常出现
NIO引入了一种基于通道(Channle)与缓冲区(Buffer)的I/O方法,它可以使用Native函数库直接分配堆外的内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能避免在Java堆和Native堆中来回复制数据的开销,本机直接内存的分配不会受到Java堆大小的限制,但是会受到物理内存的限制,所有也会抛出OutOfMemoryError异常。

小结

  1. “程序计数器”和“Java虚拟机栈”是线程私有的,而“Java堆”和“方法区”是线程共享的

  2. 除了虚拟机运行时内存,在Java中使用NIO类可以直接操作本机内存。

  3. 方法区在HotSpot中用于存放各种“常量信息”

  4. Java堆中存放了程序中所有的对象实例

女装
文章评论