Java内存详谈--堆和栈的异同

本文主要探讨一下Java内存中堆和栈不同

堆和栈

JAVA在程序运行时,内存被划分为5片空间分别是:寄存器 、本地方法区 、方法区 、栈 、堆,这里仅讨论堆和栈。

栈:用于存放基本数据类型、局部变量。

堆:用于存放实例化的对象、数组存放在堆内存中,通过垃圾回收机制回收。

通过程序来看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String args[]){

int i=0;
User user = new User();
user.setUserID(0);
change(i,user);
System.out.println(i);
System.out.println(user.getUserID());
}

public static void change(int i,User user){

i=1;
user.setUserID(1);
}

输出到结果想必不用多说吧,以下:

0
1

第一步–main()函数是程序的入口JVM在栈内存中开辟一个空间存放int类型的变量x,同时赋值为0;在堆内存中开辟一块内存用来存放user对象,userid赋值为0;

第二步–change方法用来改变两个入参的值,但是由于变量i存在栈内存中当方法调用该参数时保存现场,方法结束时,恢复现场,所以不会改变原来的值。而user在堆内存中则会改变并记录下改变过后的值。

由于基本类型变量在存储时是存在于栈内存中的,当方法调用该参数时保存现场,方法结束时,恢复现场,所以,无论方法中如何改变这个变量,结束时都不会发生变化。而user是对象,他在堆内存中,所以他的属性修改会得以保存。

再来看一段代码:

1
2
3
4
5
6
7
public static void main(String args[]){

int i=0;
int j=i;
j=1;
System.out.println(i);
}

这太简单了,答案是0不用多说,因为i和j都在栈内存中两个互不影响,int j=i;起到的是赋值的作用。所以当j变成1时,i不会收到j的影响,依然为0.

再来看下另一段代码:

1
2
3
4
5
6
7
8
9
public static void main(String args[]){

User user = new User();
user.setUserID(1);
User user2 =user;
user2.setUserID(2);
System.out.println(user.getUserID());

}

结果应该也是显而易见的,为2

但是为什么呢?这里就很好的体现堆内存和栈内存的不同,对象和基本数据类型的不同。

User user2 =user;这句话相当于将对象复制一份出来,两个对象的内存地址值一样。所以指向同一个实体,对user2的属性修改,相当于user的属性也改了。这说明在堆内存中对象是一种引用的关系,这个关系可以给 很多个变量,但是实体还是存在堆中,一旦其中一个引用对其进行修改,所有的其他的引用结果也会修改。

总结

栈存储基本类型变量,对象的引用变量都在函数的栈内存中进行分配。栈的特点是数据存活时间极短,节约内存空间。

堆中所有的实体都拥有内存地址值,当相应的实体不在被指向时及没有被引用时,JVM的垃圾回收机制会自动清理内存空间,防止内存溢出。

-->