操作数栈:常称为操作栈是一个后入先出栈。其最大的栈深度也在编译过程中就确定了并保存在Class文件的Code属性中。应用场景:在方法进行参数传递的时候是通过操作数栈进行的。 在概念模型中,两个栈帧作为虚拟机栈的袁术, 相互之间是完全独立的, 但是大多数虚拟机的实现里都会做些优化处理,使得两个栈帧出现一部分重叠。让下栈帧的部分操作与上面栈帧的部分局部变量表重叠在一起,这样在进行方法调用返回时就可以共用一分部数据,而无需进行额外的参数复制传递了。
动态连接:每个栈帧都包含一个执行运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。Class文件中存放了大量的符号引用,字节码中的方法调用执行就是以常量池中指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或第一次使用时转化为直接引用,这种转化称为静态解析。另一部分将在每一次运行期间转化为直接引用,这部分称为动态连接。
方法出口:方法出口分为两种, 一种收到返回命令,正常退出;第二种执行遇到异常导致方法退出。
虚拟机栈会出现两种异常:StackOverflowError和OutOfMemoryError
1.3 本地方法栈
本地方法栈与虚拟机栈作用非常相似,其区别不过是虚拟机栈为执行Java方法(字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。
Native方法:并不一定指Java中用native方法(如String.intern() :native方法),也包括其他库或者其他语言中的方法如C、C++。
本地方法栈也会出现两种异常:StackOverflowError和OutOfMemoryError
1.4 Java堆
Java堆是Java虚拟机所管理的内存中最大的一块。是被所有线程共享的一块内存区域,虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。几乎所有的对象实例都在这里分配内存,但随着jit编译器的发转会有微妙的变化。
Java heap 是垃圾收集器管理的主要区域。在Java中,堆被划分成两个不同的区域:新生代(Young)和老年代(Old)。新生代又被划分为三个区域:Eden空间、From Survivor空间、To Survivor空间。这样划分的目的是为了更好地管理内存中的对象,包括内存的分配以及回收。堆的内存模型如图(jdk1.6)
从图中可以看出:堆大小=新生代+老年代。其中堆大小可以通过参数-Xms、-Xmx来设置。
Java 堆会有OutOfMemoryError异常
1.5 方法区
方法区与Java堆一样,是各个线程共享的内存区域,但是存储的内容不同。方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。别名Non-Heap. 另外方法区并不是连续的,所以垃圾收集行为在这个区域是很少出现的。
方法区还包括一部分:常量池。常量池是用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。大小可以通过-XX:PermSize和-XX:MaxPermSize设置。
方法区会有OutOfMemoryError异常
总结:
1、区分下java栈、java堆和方法区分别存储内容:
public class Demo{
private String name ;
public Demo(String name){
this.name = name;
}
public static void main(String[] args){
Demo d = new Demo("test");
}
}
java堆 方法区 java栈
new Demo() Demo类信息 Demo d、局部变量name
Demo中的方法名 调用main方法主线程调用栈