1、程序计数器
当前线程所执行的字节码行号指示器
字节码指示器 通过改变这个计数器的值来选取下一条要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器完成
java虚拟机 多线程 通过线程轮流切换并分配处理器执行时间方式实现
任何一个时刻,一个处理器(多核处理器来说就是一个内核)都只会执行一条线程中的指令。
为了线程能恢复到正确的执行位置
每条线程有一条程序计数器,各个线程之间的计数器互不影响,独立存储,我们称这类内存为“线程私有”的内存
唯一没有 outofmemoryError的区域
2、java虚拟机栈
同 程序计数器 一样 为线程私有,声明周期与线程相同。
描述的是java方法执行的内存模型:每个方法调用到执行完成 对应一个栈帧 在虚拟机 入栈道出栈的过程
虚拟机栈 中 虚拟机栈 局部变量表部分
局部变量表 存放了编译期的各种基本数据类型,对象引用和 returnAddress类型(指向了一条字节码指令的地址)
编译期间完成 局部变量内存的分配,方法运行期间不会改变局部变量表的大小
如果申请的栈深度超过了虚拟机允许的最大栈深度会抛出Stack OverflowError。如果允许扩展时,当扩展时无法申请足够的内存会抛出OutOfMemoryError。使用-Xss来设置栈大小。?(如何理解深度和内存足够)
3、本地方法栈
其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。?
4、java堆
存放对方的实例,所有对象实例和数组都在堆上分配
堆是 垃圾收集器管理的主要区域,从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以java堆还细分:新生代和老年代;
再细致一点的有Eden空间,from survivor空间,to survivor空间等。
从内存分配的角度来看,线程共享的java堆可能划分出多个线程私有的分配缓冲区。
无论如何划分,都与存放的内容无关,无论哪个区域,存储的都是对象实例。进一步划分的目的是为了更好的回收内存,或更快的分配内存。
通过-Xmx -Xms动态扩展
5、方法区(Non-Heap) (方法区和堆的区别)
方法区与java堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器遍以后的代码等数据。
Java虚拟机规范把方法区描述为堆的一个逻辑部分,但它却有个别名叫做Non-Heap(非堆)
垃圾收集在这个区域比较少见,这个内存回收主要是针对常量池的回收和对类型的卸载
5.1、运行时常量池
是方法区的一部分,
Class文件出了有类的版本,字段,方法,和接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这个部分内容在类加载后紧肤方法区的运行常量池中存放。