前言
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分成若干个不同的数据区域。
程序计数器
- 是一块较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器
- 程序计数器处于线程独占区,Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任一时刻,一个处理器只会执行一条线程中的指令,当线程切换后能够恢复到正确的执行位置,因此每个线程需要有一个独立的程序计数器
- 如果线程正在执行的是Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址,如果正在执行的是native方法,这个计数器的值是undefined。这里的native方法就是一个java调用非java代码的接口。至于为什么要用?请参看《Java的native方法》
-
-
- 此区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域,因为程序计数器是Java虚拟机自己管理的区域,开发人员不需要去维护,因此,就没有规定任何OutOfMemoryError
-
-
Java虚拟机栈
- 线程私有,为虚拟机执行Java方法服务
- 描述Java方法执行的动态内存模型,每个方法执行时会创建一个栈帧,用来存放局部变量表,操作数栈,动态链接,方法出口,每一个方法从调用开始直到调用结束,都对应着入栈和出栈过程。
- 大小:方法调用时会不断的进栈,当超过栈大小时会报StackOverFlowError
- 如果虚拟机可以动态扩展,如果扩展时无法申请到足够的内存,则会报OutOfMemoryError异常
- 局部变量表:存放了编译期可知的各种基本数据类型,对象引用
本地方法栈
- 为虚拟机执行native方法服务
- 其它同java虚拟机栈
Java堆
- 线程共享
- 是Java虚拟机所管理的内存中最大的一块
- 存放对象
- Java堆,可处于物理上不连续的内存
- 既可以是固定大小的,也可以是可动态扩展的,若申请不到内存,则会报OutOfMemoryError异常
方法区
- 线程共享
- 虚拟机加载的类信息,常量,静态变量(类的版本,字段,方法,接口)
- 很少有垃圾回收
- 大小可固定也可动态分配,当申请不到足够的内存时,会报OutOfMemoryError异常
直接内存与运行时常量池
- 运行时常量池属于方法区一部分,受内存限制,当申请不到足够内存时会报OutOfMemoryError异常
- 运行时常量池用于存放编译期生成的各种字面量和符号引用
- 直接内存不是虚拟机运行时数据区的一部分,可以提高效率,避免了在Java堆和Native堆来回复制数据
- 直接内存受本机内存限制,因此会出现OutOfMemoryError异常
public static void main(String[] args) { String s1 = "abc"; String s2 = "abc"; String s3 = new String("abc"); System.out.println(s1 == s2); System.out.println(s1 == s3); System.out.println(s1 == s3.intern()); }
s1和s2放在栈区,指向常量池中的abc引用,s3是new出的对象,所以放在堆中,当使用s3.intern()方法时,会将"abc"放到运行时常量池,当运行时常量池中已经存在时,就不再往运行时常量池中存放,而是直接指向引用!