方法在执行过程当中,JVM中的内存是如何分配的呢,内存是如何变化的?
1、方法只定义,不调用,是不会执行的,并且在JVM中也不会给该方法分配"运行所属”的内存空间。
只有在调用这个方法的时候,才会动态的给这个方法分配所属的内存空间.
2、在JVM内存划分工上有这样三块主要的内存空间 (当然除了这三块之外还有其它的内存空间)
方法区内存
堆内存
栈内存
3、关于栈数据结构
栈:stack,是一种数据结构
数据结构反应的是数据的存储形态.
数据结构是独立的学科,不属于任何编程语言的范畴,只不过在大多数编程语言当中要使用数据结构。作为程序员需要提前精通:数据结构+算法 [计算机专业必修一门课程]
java程序员在不精通数据结构和算法的前提下,也可能进行java开发,因为java有一套 庞大的类库支撑,.别人写好了,直接用。[ JavasE当中的集合章节使用了大量的数据结构]
常见的数据结构: 数组 ,队列 ,链表 ,二叉树 ,哈希表/散列表 ……
4、方法代码片段存在哪里?方法执行的时候执行过程的内存在哪里分配?
方法代码片段属于. class
字节码文件的一部分,字节码文件在类加载的时候,将其放到了方法区当中。所以JVM中的三块主要的内存空间中方法区内存最先有数据。存放了代码片段。
代码片段虽然在方法区内存当中只有一份,但是可以被重复调用。
每一次调用这个方法的时候,需要给该方法分配独立的活动场所,在栈内存中分配。
栈内存中分配。(栈内存中分配方法运行的所属丙存空间)
5、方法在调用的瞬间,会给该方法分配内存空间,会在栈中发生压栈动作,方法执行结束之后,给该方法分配的内存空间全部释放,此时发生弹栈动作.
压栈:给方法分配内存
弹栈:释放该方法的内存空间
一执行就在执行时候会先执行上面一个主方法然后再执行m方法
只要方法一开始执行(比如这里的主方法一执行就会在栈内存里面分配空间,然后再为m方法分配空间,也就是造成了压栈)
main方法最先调用肯定是在栈底部,第二个调用m方法,所以m方法会压住main方法,所以m方法在执行过程当中main方法是暂停
【m方法执行到m();不能继续往下走,是等着m执行结束之后,m();才算结束,然后main方法才能继续往下执行】
只要调方法就造成压栈,方法执行结束后内存空间全部释放,这是弹栈
m方法执行到m();不能继续往下走,是等着m执行结束之后,m();才算结束,然后main方法才能继续往下执行所以i
是局部变量类型
最后调用的方法一定最先结束(是栈数据结构的特点)
这就是栈数据结构
分析以下程序的输出结果
public class yu{
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");
m3(); //暂停
System.out.println("m2 over");
}
public static void m3(){
System.out.println("m3 begin");
System.out.println("m3 over");
}
}
首先从程序入口开始执行
main begin
main begin执行完毕就到了 m1();只有 m1();执行结束下面的main over
所以先执行m1也就是去调用m1
m1 begin
同理m1执行完毕也才能执行m1 begin所以先执行m2也就是去调用m2
m2 begin
同理调用m3
m3 begin
m3 over
m3 over结束就代表m3由暂停恢复了活跃状态,所以也就执行m2 over
m2 over输出后m2就结束了
m2结束就输出m1 over
m1 over输出又表示m1结束,结束就输出main over
所以执行顺序
main begin
m1 begin
m2 begin
m3 begin
m3 over
m2 over
m1 over
main over
画出内存分配图
public class yu{
public static void main(String[] args){
int a=10;
int b=20;
int retValue=sumInt(a,b);//调用非法,因为在同一个类当中所以省略了类名.
System.out.println("retValue="+retValue);
}
public static int sumInt(int i,int j){
int result=i+j;
int num=3;
int retValue=divide(result,num);
return retValue;
}
public static int divide(int x,int y){
int z=x/y;
return z;
}
}
运行结果10
首先要执行main方法就要把yu
这个类加载到虚拟机当中
程序往下走回去调用main方法,main方法里面有String,然后一直到main方法的输出
怎样判断是不是字节码(标识符)文件
看颜色或者找lang
(如果是sum公司写的在EditPlus
中是会显示红色,但是如果是自己写的那就没有显示颜色)
在EditPlus
中,字体颜色为红色的表示一个类的名字,并且这个类是JavaSE类库中自带的,其实JavaSE类库中自带的类,比如String.class
,System.class
这些类的名也是标识符,只要是类名就一定是标识符
查看其他标识符:
在lib中找到rt.jar
并打开
点击java中的lang
点击lang
以后看见的全是字节码文件
注意:方法区内存是最先开始执行的
加载完毕也就开始从程序入口处开始执行,
然后执行栈内存:
开始执行main方法,main方法所属的内存空间在栈内存中分配
public class yu{
public static void main(String[] args){
int a=10;
int b=20;
int retValue=sumInt(a,b); //程序运行到这里
System.out.println("retValue="+retValue);
}
public static int sumInt(int i,int j){
//把a里面的10传递给i b里面20传递给j
int result=i+j;//是cpu进行计算
int num=3;
int retValue=divide(result,num);
return retValue;
}
执行到了 int retValue=sumInt(a,b);
等号右边先执行,当右边方法没有结束的时候,等号左边永远执行不了
所以会先去调用sumInt
方法,调用执行就会为它分配内存空间
sumInt
里面有两个局部变量i
与j
i
与j
里面保存的是什么东西就看 int retValue=sumInt(a,b);
这里传递过来的是什么
i
j
里面保存什么= a b
传递什么
方法调用的时候,在参数传递的时候,实际上传递的是变量中保存的那个值传过去了
此时main方法处于暂停状态,从图中也可以看出它被sumInt
压栈了,此时活跃的是sumInt
方法,会由CPU进行计算i+j=30
public class yu{
public static void main(String[] args){
int a=10;
int b=20;
int retValue=sumInt(a,b);
System.out.println("retValue="+retValue);
}
public static int sumInt(int i,int j){
//把a里面的10传递给i b里面20传递给j
int result=i+j;//是cpu进行计算
int num=3;
int retValue=divide(result,num);
return retValue;
}
所以会有一个为30的result
,注意这是一个局部变量
接着执行int num=3;
执行下一行int retValue=divide(result,num);
此时divide
执行时sumInt
处于暂停状态
它会去调用divide方法,又会发生压栈
public class yu{
public static void main(String[] args){
int a=10;
int b=20;
int retValue=sumInt(a,b);
System.out.println("retValue="+retValue);
}
public static int sumInt(int i,int j){
int result=i+j;
int num=3;
int retValue=divide(result,num);
return retValue;
}
public static int divide(int x,int y){
int z=x/y;
return z;
}
}
运行结果10
执行divide方法
执行 int z=x/y;
同样还是CPU进行计算
然后执行返回语句
return z;
public class yu{
public static void main(String[] args){
int a=10;
int b=20;
int retValue=sumInt(a,b);
System.out.println("retValue="+retValue);
}
public static int sumInt(int i,int j){
int result=i+j;
int num=3;
int retValue=divide(result,num);//执行结束
//执行结束会把值给retValue
return retValue;
}
public static int divide(int x,int y){
int z=x/y;
return z; //执行返回语句return z;
} //return z;代表 int retValue=divide(result,num);执行结束
}
继续往下return
public class yu{
public static void main(String[] args){
int a=10;
int b=20;
int retValue=sumInt(a,b);//sumInt执行结束赋值给 retValue
System.out.println("retValue="+retValue);
}
public static int sumInt(int i,int j){
int result=i+j;
int num=3;
int retValue=divide(result,num);//执行结束
//执行结束会把值给retValue
return retValue;
可以看出栈内存里面保存的是局部变量
画图依据
1、只要涉及到参数传递的问题,传递的是变量中保存的值
2、画图的时候,必须遵循方法自上而下的顺序依次执行的原则
画出程序的输出结果
public class zhang{
public static void main(String[] args){
int i=10;
method(i); //先去调用method方法然后输出method里面的i为11
//输出11以后表示method执行完毕,执行完毕就再去执行"main="+i的结果
System.out.println("main="+i);//输出10 输出的是类体中的i
//这里 System.out.println("main="+i);的i输出的是 int i=10;这里的i
}
public static void method(int i){
i++;
System.out.println("method"+i);//输出11
}
}