JVM整体示意图:
程序计数器:
- 程序计数器是一块较小的内存空间,它可以看作是当前线程执行行的字节码的行号指示器(goto可以看作是按照这个行号跳转);
- 程序计数器处于线程独占区,每一个线程都有一份;
- 如果线程执行的是Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。如果正在执行的是native方法,这个计数器的值为undefined;
- 此区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
Java虚拟机栈:
- 虚拟机栈描述的是Java方法执行的动态内存模型
- 栈帧
- 每个方法执行,都会创建一个栈帧,这个栈帧伴随着方法从创建到执行完成;
- 用于存储局部变量表,操作数栈,动态链接,方法出口等;
- 局部变量表
- 存放编译器可知的各种基本数据类型,引用类型,returnAddress类型;
- 局部变量表的内存空间在编译期完成分配,当进入一个方法时,这个方法需要在栈帧中分配多少内存是固定的,在方法运行期间是不会改变局部变量表的大小的;
- 局部变量表中存放的是一个对象的引用,所以说创建对象也不会改变它的大小(引用是一个地址)
- 虚拟机栈的大小
- 会抛出StackOverflowError
- 不限定虚拟机栈的大小会随着方法的入栈最终导致OutOfMemoryError
本地方法栈:
- 本地方法栈和虚拟机栈是很类似的;
- 区别
- Java虚拟机栈是为Java方法来服务的;
- 本地方法栈是为native方法来服务的;
- 它也一样有栈帧、局部变量表这些东西 ;
Java堆:
- Java堆就是用来存储对象实例的;
- 也是垃圾收集器管理的主要区域;
- 分为新生代、老年代等;
- -Xmx -Xms指定堆内存大小;
方法区:
- JVM只有只有一个方法区,被所有线程共享;
- 方法区实际上也是一块堆,只是用来存储类,常量相关的信息;
- 用来存放程序中永远不变或唯一的内容(类信息[Class对象]、静态变量、字符串常量等)
- 方法虚拟机存储加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;
- 类的版本
- 字段
- 方法
- 接口
- 方法区和永久代
- 垃圾回收在方法区的行为很少,回收效率低(常量池的回收,类的卸载等)
- 运行时常量池
- 运行时常量池的数据结构相当于一个HashSet,无序,不重复的
- 两个相同的字符串引用记录同一个地址
- String如果实在堆内存new出来的,调用string.intern()方法,如果常量池中有equals(s)的字符串,则返回该地址,如果常量池中没有,则在常量池中创建一个,并返回该地址