Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途、创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随线程的开始和结束而创建和销毁。
Java虚拟机运行时包含以下几个运行时数据区:
程序计数器
程序计数器是线程私有的,在线程创建时创建。可以看作是当前线程所执行的字节码的行号指示器(指向下一条需要执行的字节码指令)。
Java虚拟机栈
Java虚拟机栈是线程私有的,随线程的开始和结束而创建和销毁。Java虚拟机栈描述的是 Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就相当于一个栈帧在Java虚拟机栈中入栈到出栈的过程。
本地方法栈
本地方法栈是线程私有的,和Java虚拟机栈作用类似,Java虚拟机栈为虚拟机执行Java方法服务,而本地方法栈为虚拟机执行Native方法服务。
Java堆
Java堆是可供各个线程共享的运行时内存区域,是供所有类实例和数组对象分配内存的区域。Java堆在虚拟机启动时被创建,存储了垃圾收集器(GC)管理的各种对象,这些对象无法显式销毁。
堆内存可以细分为新生代和老年代,其中新生代再细致一点可分为Eden空间、S0空间(From Survivor)、S1空间(To Survivor)。可以通过-Xmx和-Xms控制堆内存大小。
方法区
方法区是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码数据等,例如:运行时常量池、字段和方法数据、构造函数和普通方法的字节码,还包括一些在类、实例、接口初始化时用到的特殊方法。
其中运行时常量池包含下面几种类型:
- CONSTANT_Utf8:UTF-8编码的Unicode字符串,tag为1
- CONSTANT_Integer:int类型的字面值,tag为3
- CONSTANT_Float:float类型的字面值,tag为4
- CONSTANT_Long:long类型的字面值,tag为5
- CONSTANT_Double:double类型的字面值,tag为6
- CONSTANT_Class:对一个类或接口的符号引用,tag为7
- CONSTANT_String:String类型字面值的引用,tag为8
- CONSTANT_Fieldref:对一个字段的符号引用,tag为9
- CONSTANT_Methodref:对一个类中方法的符号引用,tag为10
- CONSTANT_InterfaceMethodref:对一个接口中方法的符号引用,tag为11
- CONSTANT_NameAndType:对一个字段或方法的部分符号引用,tag为12
- ......(新版本添加了其他一些类型)