菜鸟学Java(二十三)——Java内存分析

来源:互联网 发布:西安交通大学软件学院 编辑:程序博客网 时间:2024/03/29 06:39

原博主要求附链接,尊重原创


我们常说的Java内存主要分为四大块(寄存器不在考虑之内,我们无法用代码来操控它):stack(栈)、heap(堆)、data segment(数据区)、code segment(代码区)。它们的主要用途如下图所示:




而在上面四个当中,我们经常谈论的是右边那两个家伙——stack和heap。今天我们就来聊聊Java代码在运行的过程中,在stack和heap中到底是什么样子的吧。


我们先看下面一段代码:

[java] view plain copy
  1. public static void main(String[] args) {  
  2.     TestReference testReference = new TestReference();  
  3.     int age = 1;  
  4.     Person xiaoqiang = new Person("小强"21);  
  5.     Person xiaoming = new Person("小明"22);  
  6.       
  7.     testReference.selfPlus(age);  
  8.     System.out.println("age经过selfPlus方法的处理后为:" + age);  
  9.       
  10.     testReference.changeName(xiaoqiang);  
  11.     System.out.println("小强经过changeName方法的处理后的名字为:" + xiaoqiang.getName());  
  12.       
  13.     testReference.changeAge(xiaoming);  
  14.     System.out.println("小明经过changeAge方法的处理后的年龄为:" + xiaoming.getAge());  
  15.       
  16. }  
  17.   
  18. public void selfPlus(int i) {  
  19.     i = i + 1;  
  20. }  
  21.   
  22. public void changeName(Person person) {  
  23.     person = new Person("小刚");  
  24. }  
  25.   
  26. public void changeAge(Person person) {  
  27.     person.setAge(25);  
  28. }  


执行完以上代码,会打印出什么内容呢?如果你Java基础还可以,那么很容易就能知道会输出什么内容,想要知道以上代码会打印什么内容,需要你明白Java代码在stack和heap中是怎么工作的。下面我们结合几张图来看看:

[java] view plain copy
  1. int i = 1;  
  2. Person xiaoqiang = new Person("小强"21);  
  3. Person xiaoming = new Person("小明"22);  

当我们执行完上面三行代码时,内存中的情况如下图所示:



我们知道stack是用来存放变量的,所以age、xiaoqiang和xiaoming三个变量会被存放到stack里,而age又是int类型,所以它的值也会被存放在stack里面。xiaoqiang和xiaoming为Person类型的引用变量,所以stack只会存放它们的一个引用,也就是对应对象的内存地址,而它们真正的内容被存放在了heap里面。


当执行到testReference.selfPlus(i);时,selfPlus(int i)方法被调用,此时会在stack中为形参I开辟一块内存空间,并将其值设置为1,此时内存中的情况如下:


因为调用selfPlus(int i)方法时,将age作为形参传递给该方法,相当于将age的值复制一份给i,所以现在i的值为1,接着执行i = i + 1;此时i的值被修改为2,如图:


此时被修改的只是age的副本,而并非age本身,所以age仍为1,当selfPlus(int i)方法被执行完,i被销毁,age不变。接下来看xiaoqiang,当调用changeName(Person person)方法时,会在stack中为person分配一块空间,里面存放的是xiaoqiang指向的地址,如图:


然后执行到person = new Person("小刚");时,由于又new了一个Person对象,所以在堆中会新建一个person,姓名叫小刚,并且会将person执行小刚的地址,如图:

此时,person指向的对象由小强变成了小刚,但是xiaoqiang所指向的对象仍然是小强,并没有发生任何变化。当changeName方法执行完以后,person被销毁,而小刚也会因为没有任何对象对其进行引用,随后被垃圾回收器回收掉。


下面到了最后一个方法了,当执行testReference.changeAge(xiaoming);时,调用changeAge(Person person)方法,同样会在stack中为person分配一块空间,这次里面存放的是xiaoming对应的内存地址,如图:



然后执行person.setAge(25);,此时person指向的对象为小明,所以在执行setAge方法时,修改的就是heap中小明的属性值,此时小明的年龄被修改为25,。方法执行完毕,person被销毁,内存中最终结果如下:


内存中的最终情况就如上图所示,当然当main方法执行完以后,之前创建的所有对象都会被销毁。OK,每天上班做项目的你是不是把一些基础的东西忘了呢?如果是的话就赶快来补一补吧,好处还是很多的。