java虚拟机在执行java程序的时候将自己算管理的内存划分为若干不同区域:
线程独有:
(1)程序计数器:由于java虚拟机的多线程通过线程轮流切换并分配处理器执行时间,为了线程切换后可以恢复到正确的执行位置,需要每个线程独有一个自己的程序计数器,字节码解释器通过改变这个解释器的只来选取下一条需要执行的字节码指令。
如果线程执行的是java方法,计数器记录的是正在执行的指令的地址;
如果线程执行的Native方法,则计数器值为Null。
(2)java虚拟机栈:每个方法在被执行的过程中都会创建一个栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等等信息。每个方法在被调用直至完成期间,就对应着一个栈帧从入栈到出栈的过程。需要注意的是:局部变量表所需的内存空间在编译期间完成分配,因此,在进入一个方法时,这个方法需要在栈中分配的局部变量空间早已完全确定,运行期间不会改变局部变量表的大小。
(3)本地方法栈:只针对虚拟机所使用的Native方法服务。
线程共有:
(1)Java堆:Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建,唯一目的就是为了存放对象实例,是垃圾收集器管理的主要区域。可以处于物理上并不连续的内存空间中。
(2)方法区:也是每个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、方法描述、类名、字段描述区即时编译器编译后的代码等数据。同样不需要连续的物理内存地址只需逻辑内存相连即可。主要针对常量池的回收和对类型的卸载。
常量池:方法区的一部分,用于存放编译期生成的各种字面量和符号引用,运行期间 也可将新的常量放入池中。
练习:
1)直接指针:Java堆对象的布局中就必须考虑如何防止访问类型数据的相关信息,reference中直接存储的就是对象地址。
2)句柄访问: Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的的句柄地址。
直接内存:并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域,但是这部分内存被频繁的使用,因此也一起讲解,直接内存扩展不会受到java堆的限制。但是,其受到本级总内存大小及处理器寻址空间的限制。