JAVA中栈和堆的存储区别
Java中的8大基本类型
类型 | 存储字节 | 取值范围 |
---|---|---|
byte | 1字节 | -128 ~ 127 |
short | 2字节 | -32,768 ~ 32,767 |
int | 4字节 | -2,147,483,648 ~ 2,147,483, 647 |
long | 8字节 | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
类型 | 存储字节 | 取值范围 |
---|---|---|
float | 4字节 | 约 ± 3.402,823 47E(有效位数为6 ~ 7) |
double | 8字节 | 约 ± 1.797,693,134,862,315 70E+308(有效位数为15位) |
类型 | 存储字节 | 取值范围 |
---|---|---|
char | 2字节 | u\0000 ~ u\ffff (unicode编码) |
boolean | 1字节 | true/false |
Java中栈(stack)和堆(heap)
栈的基本了解
优点:存取速度比堆要快,仅次于寄存器,栈里的数据是可以共享的。
缺点:存在栈中的数据大小与生命周期是确定的,缺乏灵活性。
存放的东西:上面的8大数据类型、对象句柄(引用)和方法函数。
堆的基本了解
优点:堆上的对象动态创建,灵活性高。
缺点:速度慢,不能及时释放内存。
存放的东西:new出来的对象。
栈与堆的存储和释放
栈存储与释放
存储:根据上面的知识我们已经知道栈存放的东西有哪些,如在一个方法swap()里面定义一个int a = 2;jvm会在栈上开辟一个未使用的内存给这个方法和变量使用。
释放:随着方法调用完后,他们的内存会立即释放,其他方法可以立即使用这个已释放的内存,这也是在栈上存储速度快的原因。
堆存储与释放
存储:堆上存储的是new出来的对象,当使用xxClass() a = new xxClass()后,对象会在堆上存储,而对象句柄a会存储在栈上,它指向的是堆上对象所在的首地址。
释放:因为对象句柄是存在栈上,而栈上的方法在调用完后会立即释放内存,这样指向堆上的引用就没有了,堆上该对象在没有引用变量指向它后变成垃圾对象,但是堆上存储该对象的内存却还没有释放,也就不能给其他新建对象使用,jvm会在一个不确定的时间里通过垃圾回收器回收这部分内存。这就是为什么Java比较占内存的主要原因。
证实栈上的方法在互不影响的内存里
public class Main {
public static void swap(int a,int b){
int t = a;
a = b;
b = t;
System.out.println("进入函数调用:a = "+a+",b = "+b);
}
public static void main(String[] args) {
int a = 2;
int b = 4;
swap(a,b);
System.out.println("调用函数返回:a = "+a+",b = "+b);
}
}
由图2可以看出main()和swap()方法在栈上是在两块互不影响的两块内存中,所以两个方法中定义的变量也是在各自分配的内存上,所以在swap中进行的任何数据操作都对main()中的变量无任何影响。
证实栈上存放的对象句柄是指向堆上存放对象的地址
class Dog{
public int age;
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return this.age;
}
}
public class Main {
public static void change(Dog dog){
dog.setAge(5);
System.out.println("进入函数调用:age = "+dog.getAge());
}
public static void main(String[] args) {
Dog dog =new Dog();
dog.setAge(2);
change(dog);
System.out.println("调用函数返回:age = "+dog.getAge());
}
}
由图3和图4可知,当创建一个对象的时候,栈上存储的是对象的引用,真正的对象数据是在堆上建立的,栈上的对象引用就指向堆上建立的对象的地址,当main()函数调用change()函数的时候是传了对象的引用过去(也就是堆上对象的地址),然后在change()方法中根据传过来的地址去修改堆上的对象数据,所以即使当栈上change()方法被释放后,堆上的对象数据是已经改变后的。
提出一个问题,String不在Java的8大基本类型中,而且String的定义有两种方式,那么它是存在栈上还是在堆上呢?
提示一下:在栈上有个String常量池的,也就是说相同的字符串在常量池中只存放一份。可以使用(str1 == str2)来看地址的是否相同。
如果只是向往,远依旧是远方。