一. Java内存的分配
当Java 程序运行时,对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
1. 栈:储存局部变量 (基本数据类型的值;类的实例,即堆区对象的引用(指针);
特点:栈内的数据用完就释放掉
2. 堆:储存 new 出来的对象(即对象实例)及数组 ;
注:
jdk 1.7常量属于堆内存的一部分。
Java8移除了永久代并由元空间(metaspace)代替,存放在本地内存(native space)中。并没有对常量池再做变动。即常量池一直在堆中。
特点:(1)new出来的变量都是有地址值的
(2)每一个变量都有默认值:
byte,short,int ,long : 0;
float,double:0.0;
Boolean:false ;
引用类型:null;
(3)new出来的对象,使用完毕,会被垃圾回收器回收。
3. 常量池:常量池本身是方法区中的一个数据结构。
Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。
静态常量池,即*.class文件中的常量池,占用class文件绝大部分空间。
运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。
常量池的好处
常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。
例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
(1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。
(2)节省运行时间:比较字符串时,==比equals()快。
对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。
4. 方法区:存放类信息和运行时常量池。
注: java8中,方法区存放于元空间(Metaspace),直接存放于本地内存
说明:
字面量:java代码在编译过程中是无法构建引用的,字面量就是在编译时对于数据的一种表示: int a = 1; //这个1便是字面量
符号引用:由于在编译过程中并不知道每个类的地址,因为可能这个类还没有加载,所以如果你在一个类中引用了另一个类,那么你完全无法知道他的内存地址,只能用他的类名作为符号引用,在类加载完后用这个符号引用去获取他的内存地址。
说明:
PC寄存器/程序计数器是jvm执行程序的流水线,存放一些跳转指令。
本地方法栈是jvm调用操作系统方法所使用的栈。
字符串常量池原本存放于方法区,jdk7开始放置于堆中。存储的是string对象的直接引用,而不是直接存放的对象,是一张string table
静态变量是有static修饰的变量,jdk7时从方法区迁移至堆中