按照编译原理的观点,程序运行时的内存分配有三种策略:
分别是“静态存储分配”“栈式存储分配”和“堆式存储分配”。
堆主要用来存放对象的,栈主要是用来执行程序的。
在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。
下面是我对一个程序执行的分解:
//定义一个Leaf 类
public class Leaf {
//定义并赋值了一个int型的成员变量 i
int i = 0;
//构造函数
public Leaf(int i) {
给 i 赋值
this.i = i;
}
//定义了一个叫“increament”的方法
Leaf increament() {
//i 自加
i++;
//将值返回给 i (成员变量)
return this;
}
//定义了一个叫“paint”的方法
void paint() {
//打印输出 i
System.out.println("i = " + i);
}
//main 入口
public static void main(String[] args) {
Leaf leaf = new Leaf(100); //首先:new Leaf(100)在“堆”里申请了一坨内存,
//把创建好的Leaf对象放进去 ,并且给“栈”中的变量“i”传值
// 那么 i = 100 ;
//然后:leaf 等于号(赋值符号)把两者关联起来,这样
//Leaf对象在堆中的地址就存储在了变量 leaf 中
leaf.increament().increament().paint();
//先执行leaf.increament()函数,然后执行increament()函数,最后执行paint()函数
}
}
运行:
1.程序从main 开始执行
Leaf leaf = new Leaf(100);
分解:
1.1 Leaf leaf :在“栈”中创建了一个叫leaf的变量 ,
1.2 new Leaf:在“堆”中创建了一个“Leaf”对象,并把Leaf的属性写人
(在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 )
1.3 Leaf(100):执行Leaf 的构造方法
public Leaf(int i) {
this.i = i ;
}
1.4 在栈中定义了一个参数 int i ,并且赋值 i = 100 ;
1.5 this.i = i ; 给成员变量 i 赋值 i = 100;
1.6 出了构造函数,参数 int i 被销毁 ;(当超过变量的作用域后,Java会自动释放掉为该
变量所分配的内存空间,该内存空间可以立即被另作他用)。
1.7 Leaf leaf = new Leaf(100) ,在变量leaf 存入 Leaf 在堆中的地址。
在栈中定义的变量“leaf”,“leaf”值等于对象Leaf在堆内存中的“首地址”,则“leaf”变量就
成了对象“Leaf”的引用变量。
2 . 执行leaf.increament().increament().paint();
分解:
2.1 先执行函数 leaf.increament()
Leaf increament() {
i++;
//i= i + 1
//i = 100 + 1
return this;
}
执行完后,i= 101
2.2 再执行increament()
Leaf increament() {
i++;
//i= i + 1
//i = 100 + 1
return this;
}
执行完后,i= 102
2.3 最后执行 paint()
void paint() {
System.out.println("i = " + i);
}
输出 i = 102 ;
总结:
堆:
优势:
可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动回收这些不再使用的数据。
缺点:
由于要在运行时动态分配内存,存取速度较慢。
栈:
优势:
存取速度比堆要快,仅次于寄存器,栈数据可以“共享”。
缺点:
存在栈中的数据大小与生存期必须是确定的。
缺点:
缺乏灵活性。(栈中主要存放一些基本类型的变量和对象句柄)
如有错误,还请指正,谢谢