java的GC机制--java的内存区域

来源:互联网 发布:淘宝商城百丽旗舰店 编辑:程序博客网 时间:2024/06/04 23:02

了解java GC 机制,必须搞清楚JVM中内存区域的划分,在java运行时的数据区域里,由JVM管理的内存区域主要分成一下几块:













1、程序计数器(Program Counter Register):程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到第几行,可以理解为当前线程的行号指示器。字节码指示器工作是,会通过改变这个计数器的值来取下一条语句指令。

每个程序计数器只用来记录一个线程的行号,所以它是线程私有的。

如果程序执行的是一个java方法,那么程序计数器记录的就是正在执行的虚拟机字节码的指令地址;如果执行的是本地方法,那么计数器的值为undefined;由于程序计数器只记录当前指令地址,所以不存在内存溢出的情况,应此程序计数器也是JVM内存区域内唯一没有定义OutOfMemoryError的区域

2、虚拟机栈(JVM Stack):一个线程的每个方法在执行时,都会创建一个栈帧,栈帧中储存的有局部变量表、操作站、动态链接和方法出口,当方法被调用时,栈帧在虚拟机栈中入栈,当方法完成执行时,栈帧出栈。

局部变量表中储存着方法的相关局部变量,包括基本数据类型、变量的应用和返回地址等,局部变量表中,只有long和double变量类型会占用两个局部变量空间。需要注意的是,局部变量表是在编译时就已经确定好的,方法运行所需要的空间在栈帧中是完全确定的,在方法的声明周期内不会改变。

虚拟机栈中定义了两种异常:如果线程调用的栈深度大于虚拟机允许的最大深度,则抛出StackOverFlowError(栈溢出),多数虚拟级允许动态扩展虚拟机栈的大小,所以线程可以一直申请栈,知道内存不足,此时,会抛出OutOfMemorryError(内存溢出);

每个线程对应一个虚拟机栈,所以虚拟机栈也是线程私有的;

3、本地方法栈(Native Mothed Stack):本地方法栈在作用,运行机制,异常机制方面都与虚拟机栈相同,唯一的不同是:虚拟机栈执行的是java方法,本地方法栈用来执行native方法的,在很多虚拟机中会将虚拟机栈和本地方法栈连载一起使用

本地方法栈也是线程私有的

4、堆区(Heap):堆区是理解GC机制最重要的区域。在JVM管理的内存中,堆区是最大的区域,堆区是javva GC 管理机制所管理的主要内存区域,堆区由所有线程共享,在虚拟机启动时创建,堆区的存在是为了存储对象实例,原则上讲,所有对象都在堆区上分配内存(也有直接在栈上分配内存的);

一般的,根据java虚拟机规范规定,堆内存需要在逻辑上要是连续的(物理上可不连续),在实现是,可以是固定大小的,也可以是可扩展的,目前主流虚拟机都是可扩展的。如果在垃圾回收后,仍没有足够的内存分配,也不能再分配,此时会抛出OutOfMemorryError:Java head Space异常。

堆区是线程共享的。

5、方法区(Method Area):在java虚拟机规范中,将方法区作为堆的一个逻辑部分来对待,但事实上方法区不是堆;

方法区是所有线程的共享区,用于储存已经被虚拟机加载的类信息(即加载类时需要加载的信息,包括版本、field、方法、接口等信息)、final常量、静态变量、编译器即时编译的代码等。

方法区在物理上也不需要是连续的,可以选择固定大小也可选可以扩展,并且方法区比堆区多一个限制:可以选择是否执行垃圾收集。一般的,方法区上执行的垃圾回收是很少的,这也是方法区被称为永久代的原因之一(HotSpot),但这也不代表着方法区上完全没有垃圾回收,其上的垃圾回收主要针对常量池的内存回收以及对以加载的类卸载。

方法区上的垃圾回收,条件苛刻且相当困难,效果也不尽如人意,所以一般不做过多考虑。

在方法区上定义了OutOfMemoryError:Permgen Space异常;内存不足时抛出。

运行时常量池(Runtime Constant Pool)是方法区的一部分,用于存储编译期就生成的字面常量、符号引用、翻译出来的直接引用(符号引用就是编码是用字符串表示某个变量、接口的位置,直接引用就是根据符号引用翻译出来的地址,将在类链阶段翻译完成翻译)。运行时常量池除了存储编译期常量外,还可以存储运行时产生的常量(比如String类的interm()方法,作用是String维护了一个常量池,如果调用的字符“aaa”已在常量池中,则返回常量地址,否则,新建一个常量加入常量池,再返回常量地址).

方法区是线程共享的。

6、直接内存(Dirict Memory):直接内存并不是JVM直接管理的内存,就是JVM意外的内存。JDK中有一种基于通道(channel)和缓冲区(buffer)的内存分配方式,将由C语言实现的native函数库分配在直接内存中,用储存在JVM中的DirectByBuffer引用,由于直接内存受到本机内存的限制,也可能会抛出OutOfMemorryError异常。


原创粉丝点击