1. 程序计数器
程序计数器是一块较小的内存空间。它可以看作是当前线程所执行的字节码的行号指示器。字节码9解释器工作时就是通过改变这个计数器的值来取下一条需要执行的字节码指令,分支循环跳转,异常处理,线程恢复的基础功能,都需要依赖这个计数器来完成。
java虚拟机栈,平时我们讲的堆栈中的栈。每个方法在执行的同时,都会创建一个栈桢,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法从调用到返回,就对应着一个栈桢在虚拟机栈中入栈和出栈。虚拟机栈中的局部变量表存放了编译期可知的基本数据类型,对象引用类型等。这里的对象引用类型存放的并不是对象本身可能是指向一个对象起始地址的引用指针(如指向堆空间中的对象地址等)。
java虚拟机栈一般有两种异常情况。一种是StackOverflowError表示线程请求的栈深度大于虚拟机所允许的深度。另一个是OutOfMemoryError,表示扩展时无法申请到足够的内存。
3. 本地方法栈
本地方法栈和虚拟机栈所发挥的作用大致相同,唯一的区别是虚拟机栈为虚拟机执行java方法(我们自己编写的方法)服务,而本地方法栈则为虚拟机所用的本地方法服务。
注意: 虚拟机栈和本地方法栈都为线程所私有。
4. java堆
java堆是java虚拟机所管理的内存中最大的一块。所有的对象实例均在java堆上分配。并且java堆也是垃圾收集器,即GC管理的主要区域。为了便于内存回收,所以大部分垃圾收集器也把java堆也分为新生代和老年代。(这里把永久代即方法区放在后面讲)(新生代一般指很快被回收不太大的对象,老年代指几次回收都没有被回收的对象,大的对象也直接进入老年代,比如长数组)。
注意: java堆是所有线程共享的一款内存区域, 我们可以在虚拟机启动时,通过-Xmx -Xms命令合理控制堆的大小。
5. 方法区
方法区主要存储已被虚拟机加载类的信息,常量,静态变量,即时编译器编译后的代码等数据。虚拟机规范把方法去描述为堆的一个逻辑部分。很多人把方法区成为永久代。但java虚拟机规范,并不强制要求的方法去实现垃圾收集。(原因是在方法区进行垃圾收集效率比较差,方法区回收的两部分主要是废弃常量和无用的类,但判断这两个标准非常的麻烦,比如如何判断一个无用的类,首先,这个类的所有实例都要被回收,另外,加载这个类的类加载器也应该要被回收,最后,这个类的Class模板没有被任何地方所引用,保证其不会被反射出来)注意:
注意:方法区和java堆一样,是被所有线程所共享的。
6. 运行时常量池