java变量在内存分配原理

  程序变量如何在内存分配的?其值又存放在哪里?下面以java为语言基础讲解

  一、基本原理

  例:int a = 10;

    boolean b = false;

  上面例子有两行语句,分别定义了变量a(int型,在32位系统中是4位字节),b(布尔型,只占1个字节)。都是基本类型,占位长度确定,内存分配如下:

  

内存地址

0x01

10

0x02

0x03

0x04

0x05

false

  

上面表格代表内存分布图,每一行代表1个字节,10是int型,4个字节,故占用4个地址,变量a只存首地址,然后根据长度就能找到以下所有内存地址(连续取4个字节),就能取对应的值了。false是1个字节,故只占一行。

 

java编译器编译时,会对所有变量存入一个叫符号表,符号表就是变量映射为值内存地址的表。如下

变量名

内存地址

a

0x01

b

0x05

java解释器在运行时,会把符合表中所有变量名都替换为实际内存地址,这样就可以直接找到真正内存值了。

 

  二、java堆栈中内存如何分配和释放?

  在前一篇已提到,java堆栈是由java堆栈指针上下移动操作就代表了创建/释放内存空间。还是举个例子说明:

  void fun() {

    int a = 12;

    int b = a;

    int c = 12;

    int d = 13;

  }

  内存分配如下图:

  内存地址表:

  

内存地址

0X01

12

0X02

0X03

0X04

0X05

13

0X06

0X07

0X08

  符号表:

  

变量名

内存地址

a

0X01

b

0X01

c

0X01

d

0X05

  工作原理:

  1。int a = 12; 在堆栈里查找是否有包含12的值,如有包含则直接返回12的内存地址,如无包含则新创建该值,堆栈指针往上移,并返回12的引用地址(0X01)。

  2。int b = a; 直接将符合表里的a内存地址赋于b。

  3。int c = 12; 在堆栈里查找是否有包含12的值,已经找到则返回12引用地址。

  4。int d = 13; 在堆栈里查找是否有包含13的值,没找到则新创建并返回内存地址。

  当执行到方法最后},代表该方法生命周期结束,方法内所有变量应该释放,释放过程是堆栈指针往下移,先释放d,再释放c,再到最后a。从上面过程可看出,堆栈值具有共享特性,它的值只会存一份,这也节省了内存空间。另外当变量要修改值时,如a = 20;先会找堆栈里是否有20值,如有则把引用地址替换到符号表a的内存地址里,这也不会干预到其他变量的引用。

 

  三、java堆中内存如何分配和释放?

  java堆是存放引用类型的,创建一个引用类型实例,实质是创建了两个地址空间,一个是存放对象(主要是存类字段)本身的堆里,一个是存放对象的引用地址,放在堆栈里,例:

  Object o1 = new Object();

  Object o2 = new Object();

  Object o3 = o1;

  内存分布图:

  堆区

 

内存地址

对象

0X01

O1的实质内容

0X02

O2的实质内容

  

栈区

 

变量名

内存地址

O1

0X01

O2

0X02

O3

0X01

   符号表跟上面一样,就不画了,直接在栈区里用变量名代替,工作过程如下:

  1。Object o1 = new Object(); 在堆里创建Object对象并分配内存空间,再在堆栈里创建变量o1,并存放刚堆里创建的引用地址(0X01)。

  2。Object o2 = new Object(); 在堆里创建Object对象并分配内存空间,再在堆栈里创建变量o2,并存放刚堆里创建的引用地址(0X02)。

  3。Object o3 = o1; 在堆栈里创建变量o3,并存放o1的引用地址。

  由上面可得,如更改o1的属性,则同样会更改o3,因为它们两都指向同一对象,这跟上面更改堆栈里的值不一样,堆栈里的值是原子操作,相当于一个副本,互不干扰。

  当执行完生命周期结束后,会立即释放堆栈里的空间,也就是o1,o2,o3里存放的引用地址会清零,而堆里的实质对象不会释放,要等到GC工作后才会释放,GC确定释放前,会执行每个对象的finalize()方法,该方法是Object继承来的,java所有类都继承Object根类。关于GC工作原理留在后续讲。

 

posted @ 2016-04-22 06:31  司马逍遥  阅读(1310)  评论(0)    收藏  举报