最近在复习java虚拟机相关的知识,于是做了一个有关内存区域的一个小小的总结。
一,程序计数器
1. 程序计数器(Program Counter Register)是一块较小的内存空间,字节码解释器工作就是改变这个计数器的值来选取下一条需要执行的指令。
2. 每个线程都需要有一个独立的程序计数器。
3.如果线程执行的是一个Native方法,这个计数器的值为空,所以此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
二,Java虚拟机栈
1. 首先,虚拟机栈是线程私有的,生命周期与线程相同。
2. 虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
3. 局部变量表所需的内存空间在编译期完成分配,当进入方法时局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
4. 有两种异常状况:StackoverflowError和OutOfMemoryError异常。
三,本地方法栈
1. 与虚拟机栈相似,不同之处:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,本地方法栈为虚拟机使用到的Native方法服务。
2.有的虚拟机会把本地方法栈和虚拟机栈合二为一,比如Sun HotSpot。
四,Java堆
1.虚拟机所管理的内存中最大的一块,被所有线程共享的一块区域,在虚拟机启动时创建。
2.几乎所有的对象实例和数组都在这里分配内存。
3. Java堆是垃圾收集器管理的主要区域。
4.分为新生代和老年代,再细致一点:Eden,From Survivor,To Survivor。
5. Java堆可以处于物理上不连续的内存空间,主流的虚拟机都是按照可扩展来实现的(-Xmx,-Xms控制)。
五,方法区
1. 用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
2. 相对而言,垃圾收集行为在这个区域是比较少见的,回收的主要目标是针对常量池的回收和对类型的卸载,但回收成绩一般很难令人满意。
3.运行时常量池是方法区的一部分,用于存放编译期生成的字面量和符号引用。静态域也是方法区的一部分。
六,直接内存
1. 直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。
2. 它是使用Native函数库直接分配的堆外内存,所以不会受到Java堆的限制,但因为会占用本机总内存,所以经常被忽略而导致OutOfMemoryError。
补充
1.对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
这也就是有道面试题:String s = new String(“xyz”);产生几个对象?一个或两个,如果常量池中原来没有”xyz”,就是两个(首先检查常量池中是否已经有xyz对象,如果没有则在常量池中创建一个此字符串对象,然后再在堆中创建一个该对象的拷贝)。
常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。jdk编译时会将字符串池并入常量池。
2.