简单说一下,最上方低地址的是一个特殊区域,一般存储静态变量、常量等。往下是堆(heap),主要存储在程序中动态创建和释放的实例,即对象。它是从低地址向高地址增长的。最下方高地址的是栈,存储像局部变量这样编译器自动分配的内存。有个问题,一个往上增长,一个往下,那它们会不会“相撞”呢?答案是“嗯,会的,一旦发生则会出现互相修改数据的情况= =”,但是这种事件发生的概率很小,暂时不做讨论。
那么java程序运行的时候内存的分配是什么样子的呢?咱举个例子看一看,以小见大,一目了然~~
上代码~~首先是Point类:
public class Point {
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public void move(int dx,int dy){
x+=dx;
y+=dy;
}
很简单,一个点,横纵坐标两个属性。move方法是堆点位置的移动。现在执行下面的方法:
public void run(){
Point p1 = new Point(2,3);
Point p2 = new Point(4,5);
p1.move(1, 2);
}
接下来就详细给大家说说内存是如何分配运作的~~
首先执行前两行语句,Point p1 = new Point(2,3);、Point p2 = new Point(4,5);,创建一个Point对象,此时内存是这样子滴:
左边堆存储对象,每个对象首先是一份额外的内存,然后是各个成员变量的内存空间,右边的栈是局部变量即对象引用p1、p2的内存空间(p1、p2为方法run的局部变量),同样起始也有一段额外内存空间,p1、p2的值为对应的对象在堆上的地址值,即引用指向对应的对象。
然后看看p1.move(1, 2);的执行,执行方法,首先在栈上开辟参数dx、dy变量的内存,还有一个this的内存,它是一个引用,指向被调用方法的对象(不然不知道哪个对象被调用= =),同样起始位置有一段额外空间:
然后x+=dx;y+=dy;被执行,内存变成:
堆上x,y的值被修改。注意move方法执行完毕后,栈上的对应的局部变量将出栈,即被释放。
加入现在有个线的类Line,代码如下:
public class Line {
private Point beg;
private Point end;
public Line(Point beg, Point end) {
this.beg = beg;
this.end = end;
}
}
run方法最后加一句Line line = new Line(p1, p2);,如下:
public void run(){
Point p1 = new Point(2,3);
Point p2 = new Point(4,5);
p1.move(1, 2);
Line line = new Line(p1, p2);
}
执行这一句的时候,首先在栈上开辟Line的引用line,因为构造方法是方法,拥有局部p1、p2,故先在栈上开辟这两个参数的内存,然后在堆上开辟Line对象内存,两个成员变量是两个Point的引用,然后将栈上局部变量p1、p2的值赋给beg、end。如下图:
这样beg、end指向p1、p2指向的两个对象,随着构造方法执行完毕,Line的引用line也会指向Line对象,而局部变量p1、p2也会出栈,如下图:
当整个run方法执行完毕后,栈上的局部变量将全部出栈,堆上的对象仍然存在,直到垃圾回收器将其自动回收。
以上就是一个简单java程序执行对应的内存分配过程,希望大家看了有所收获,能起到抛砖引玉的效果就心满意足了。欢迎大家提出疑问或者指出里面有误的地方~~