Java按照数据类型的不同,将数据分为基本数据类型和引用数据类型
1 基本数据类型和引用型数据类型
其中基本数据类型有8中:int char short byte long double boolean float
除了这8种之外的都是引用型数据类型
数据类型的不同,JVM对其的存储方式也是不同的,对于基本数据类型,在内存中声明一个空间a,则内存空间中存放的就是基本数据的实际值
而针对引用型数据类型,在内存中声明一个空间s,咋该内存空间中存放的是引用型数据类型实例存放在内存中的地址信息。
因此在访问基本数据类型和引用型数据类型的方式也不同,对于基本类型,一次读取即可拿到实际值;而对于引用型数据类型,需要两次读取,第一次先拿到对象实际存储位置的地址,在根据这个地址,进行第二次读取获取到实际值
2 内存分布
数据所在的位置不同,那么它们在JVM内存中的分布也就不太,但是总的来说,对于引用型数据类型而言,这个对象往往会存放在堆内存中,对于基本数据类型而言,所获即所得,它们往往存放在栈中,但是并不是说全部都是这样子的
public class Test{
static int staticInt = 1; // 1)
static Map map1 = new HashMap(); // 2)
int a1 = 3; // 3)
Map map2 = new HashMap(); // 4)
pubic void method(){
int a3 = 1; // 5)
Map map3 = new HashMap(); // 6)
}
}
上面是一段代码,既有基本数据类型,又有引用型数据类型,其中:
1)是静态基本数据类型,属于类变量,类变量是存放在方法区内存中
方法区,也称非堆(Non-Heap),又是一个被线程共享的内存区域。其中主要存储加载的类字节码、class/method/field等元数据对象、static-final常量、static变量、jit编译器编译后的代码等数据
2)是类变量,且是引用型数据类型,因此它存在两段内存空间,map1代表的内存空间里面存放的是对象地址信息,这部分区域在方法区中;而new HashMap()
对象的存储空间是放在堆内存中,由a1中的地址指向这块内存区域
3)是成员变量,且为基本数据类型,它在使用时需要依附于Test对象,且线程共享,因此它是存放在堆内存中
4)是成员变量,且为引用型数据类型,因此它存在两段内存空间,且需要依附于Test对象而存在。因此map2代表的内存空间里面存放的是对象地址信息,存放在堆内存中;new HashMap()
对象的存储空间也是堆内存,属于new出来的实例化对象
5)a3是方法内部的局部变量,且属于基本数据类型,它只有一段内存空间,因此它是存放在栈中的,不为其他线程所共享
6)map3属于局部变量,且为引用型数据类型,有两段内存空间有关,map3代表的内存空间存放对象的地址,放在栈中;new HashMap()
对象存放在堆内存中。
3 垃圾回收
JVM会回收无用的对象,我们重点关注一下堆内存的垃圾回收。
堆内存中的对象的来源:可能是成员类变量实例化的结果、也有可能是方法内局部变量实例化的结果,对于方法区中实例化的对象,我们知道方法一旦执行完毕,那么在其内部声明的局部变量也会生命终结,但是他们产生的实例化对象不一定生命终结。如,map3代表的对象:
执行完method()方法之后,map3代表的内存空间将会被回收,因此map3生命结束,但是它在堆内存中new处理的Map对象,并不一定会被回收,原因在于,可能会有其他引用指向这个对象。