文章目录
前言
想要真正掌握Java,内存分析是必要的,一旦掌握内存的分配,在程序没有运行之前我们就可以很精准的预测到程序的执行结果。这篇文章要讲解的是程序的内存,例如:代码片段被存储在什么位置?方法调用的时候,在哪开辟内存空间等等。
一、JVM内存结构
下图是JVM标准内存结构图。
目前,我们只关注**“栈”和“方法区”。
Java程序开始执行的时候先通过类加载器子系统找到硬盘上的字节码(.class文件),然后将其加载到JVM的方法区当中,开始调用main方法,main方法被调用的瞬间,会给main方法在“栈”内存中分配所属的活动空间,此时发生压栈动作,main方法的活动空间处于栈底。
由于栈的特点是先进后出**,所以最先调用的方法(最先压栈)一定是最后结束的(最后弹栈)。所以main方法最先被调用,那么它一定是最后一个结束的。换句话说,main方法结束了,程序也就结束了。
二、分析程序的内存变化
public class MethodTest {
public static void main(String[] args) {
System.out.println("main begin");
m1();
System.out.println("main over");
}
public static void m1(){
System.out.println("m1 begin");
m2();
System.out.println("m1 over");
}
public static void m2(){
System.out.println("m2 begin");
System.out.println("m2 over");
}
}
运行结果如下:
我们来分析一下该段代码的内存变化,如下图所示:
采用文字描述如下:
- 类加载器将class文件加载到方法区
- 开始调用main方法,在栈内存中给main方法分配空间,开始执行main方法,输出“main begin”
- 调用m1()方法,在栈内存中给m1()方法分配空间,此时m1()方法处于栈顶,具有活跃权,输出“m1 begin”
- 调用m2()方法,在栈内存中给m2()方法分配空间,此时m2()方法处于栈顶,具有活跃权,输出“m2 begin”,继续输出“m2 over”
- m2()方法执行结束,内存释放,弹栈
- m1()方法这时处于栈顶,具备活跃权,输出“m1 over”
- m1()方法执行结束,内存释放,弹栈
- main()方法处于栈顶,具备活跃权,输出“main over”
- main()方法执行结束,内存释放,弹栈
- 栈空,程序结束
总结
方法体中代码的执行是有顺序的,必须遵循自上而下的顺序依次逐行执行,也就是说当前行代码必须执行结束,下一行代码才能执行,不能跳跃执行。那么,我们再结合栈的数据结构一起联系起来思考,采用栈数据结构的原因就很清晰了,只有采用这种先进后出的栈的数据结构才能保证代码的执行顺序。