1.什么是内存
内存是是一段连续的存储空间,主要用来存储程序运行时数据的。比如:
:::info
- 程序运行时代码需要加载到内存
- 程序运行产生的中间数据需要存放在内存
- 程序中的常量也要保存在内存
- 有些数据可能需要长时间存储,而有些数据当方法运行结束后就要被销毁
:::
如果对内存中存储的数据不加区分的随意存储,那对内存管理起来将会非常麻烦。因此,JVM对所使用的内存按照功能的不同进行了划分。
2.JVM内存分布
- Java虚拟机栈:与方法调用相关的信息,每个方法在执行的时候,都会先创建一个栈帧,栈帧中包括:局部变量表、操作数栈、动态链接、返回地址以及一些其他信息,保存的都是与方法执行相关的信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
- 堆:JVM所管理的最大内存区域。使用new创建的对象都是在堆上保存(例如:new int[]{1,2,3,4} ),堆是随着程序运行时而创建,随着程序的退出而销毁,堆中的数据只要还在被使用,就不会销毁。
- 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法编译出的字节码就是保存在这个区域。
- 本地方法栈:本地方法栈与虚拟机栈的作用类似,只不过保存的内容是Native方法的局部变量。
- 程序技术器:只是一个很小的空间,保存下一条执行指令的地址。
3.举例介绍堆和Java虚拟机栈这两块空间
3.1基本数据类型变量
基本数据类型创建的变量成为基本变量,该变量空间中直接存放的是其所对应的值。
public static void func() {
int a = 10;
int b = 20;
}
在执行func()方法的时候,会在栈(Java虚拟机栈)上为fun()方法开辟一个栈帧,a、b都是在方法内部定义的变量,属于局部变量,局部变量存在栈里,因此a、b所对应的空间都在fun()方法对应的栈帧中分配,又由于a、b是基本数据类型的变量,因此在空间中存放的是10、20。
3.2引用变量
引用变量一般称为对象的引用,其空间中存储的是对象所在空间的地址。
public static void main(String[] args) {
int[] array = {1,2,3,4};
}
开始执行main方法时,会在栈上为main方法开辟一块栈帧,array是局部变量,所以在main方法的栈帧上为array开辟一块内存,此时会在堆上为array的对象开辟一块内存,存放数组对象,假设array数组对象的地址为0x98,那么array里面会把对象在堆空间的地址0x98存进去,也就是说,array这个引用指向了这个数组对象。
当main方法执行结束后,栈上为main方法开辟的栈帧就会被回收,同时,堆上的对象也会被回收。
那么,下面这段代码又表示什么意思呢?
public static void main(String[] args) {
int[] array = {1,2,3,4};
int[] array2 = array;
}
首先在栈中为array2开辟一块内存空间,将array的值0x98给array2,那么array2这个引用就指向了这个数组对象。此时,两个引用同时指向了一个对象。
注意:引用不能指向引用。array2这个引用指向了array这个引用所指向的对象。
接下来,我们再看一个例子:
public static void func() {
int[] array1 = new int[3];
array1[0] = 10;
array1[1] = 20;
array1[2] = 30;
int[] array2 = new int[]{1,2,3,4,5};
array2[0] = 100;
array2[1] = 200;
array1 = array2;
array1[2] = 300;
array1[3] = 400;
array2[4] = 500;
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i]);
}
}
当代码执行到array2[1] = 200时,内存中的情况如下:
当执行array1 = array2时,将array2的值给array1,此时array1就指向了地址为0x98的对象
因为两个引用同时指向了一个数组对象,所以不管通过那个引用,都可以把数组对象中的值进行修改。
当func方法执行完毕后,栈帧就会被销毁,array1和array2两个局部变量会被回收掉,堆上的对象也会被回收。
3.3总结
- 局部变量的作用域:在方法里面,生命周期:调用方法的时候创建,方法调用结束后销毁
- 当对象没有人指向时,会被JVM自动回收
- 一个引用指向一个对象是指这个引用存储了这个对象所在空间的地址