您的位置:首页 > 编程语言 > Java开发

Java中的堆、栈、方法区、运行时常量池的简单介绍

2017-09-16 00:00 295 查看
在上次我们简单介绍了Java的反射机制,在学习Java的反射的时候,我们有一张Java内存的模型图,如下:



现在我们来简单讲讲这个内存模型图中的堆、栈、方法区吧!

栈(stack)与堆(heap)都是Java用来在RAM中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。

Java栈:

每一条 Java 虚拟机线程都有自己私有的 Java 虚拟机栈(Java Virtual Machine Stack),这个栈与线程同时创建,用于存储栈帧。Java 虚拟机栈的作用与传统语 言(例如 C 语言)中的栈非常类似,就是用于存储局部变量与一些过程结果的地方。另外,它在 方法调用和返回中也扮演了很重要的角色。因为除了栈帧的出栈和入栈之外,Java 虚拟机栈不会再受其他因素的影响,所以栈帧可以在堆中分配,Java 虚拟机栈所使用的内存不需要保证是连续的。

在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。

Java堆:

在Java虚拟机中,堆(Heap)是可供各条线程共享的运行时内存区域,也是供所有类实例和数组对象分配内存的区域。Java 堆在虚拟机启动的时候就被创建,它里面存储了被自动内存管理系统(即我们常说的垃圾回收器)所管理的各种对象。Java 堆的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。Java 堆所使用的内存不需要保证是连续的。

方法区:

在Java虚拟机中,方法区(Method Area)是可供各条线程共享的运行时内存区域。它存储了每一个类的结构信息,例如运行时常量池、字段和方法数据、构造函数和普通方法的字节码内容、还包括一些在类、实例、接口初始化时用到的特殊方法。方法区的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。方法区在实际内存空间中可以是不连续的。

运行时常量池:

运行时常量池(Runtime Constant Pool)是每一个类或接口的常量池的运行时表示形式,它包括了若干种不同的常量:从编译期可知的数值字面量到必须运行解析后才能获得的方法或字段引用。运行时常量池扮演了类似传统语言中符号表的角色,不过它存储数据范围比通常意义上的符号表要更为广泛。每一个运行时常量池都分配在 Java 虚拟机的方法区之中,在类和接口被加载到虚拟机后,对应的运行时常量池就被创建出来。

从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的。堆内存用来存放由new创建的对象和数组,在堆中分配的内存,由JVM的自动垃圾回收器来管理。而栈的优势是,存取速度比堆要快,仅次于寄存器。栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。

异常情况:

如果线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量时,Java 虚拟机将会抛出一 个 StackOverflowError 异常。

如果 Java 虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是目前无法申请到足够的内存去完成扩展,或者在建立新的线程时没有足够的内存去创建对应的虚拟机栈,那Java 虚拟机将会抛出一个 OutOfMemoryError 异常。

如果实际所需的堆超过了自动内存管理系统能提供的最大容量,那Java 虚拟机将会抛出一个 OutOfMemoryError 异常。

如果方法区的内存空间不能满足内存分配请求,那 Java 虚拟机将抛出一个OutOfMemoryError 异常。

当创建类或接口的时候,如果构造运行时常量池所需要的内存空间超过了方法区所能提供的最大值,那 Java 虚拟机将会抛出一个OutOfMemoryError 异常。

最后,我感觉知识越学越深,理解一个概念的同时,要知道好几个概念才能明白这个概念。也许这就是驱动自己学习的一个方法吧!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息