-
堆(heap)
1.类的所有对象都放在堆中,也就是我们通过new方法所创建的对象都存放在堆中,同时栈会创建堆中类对象的(内存地址),而栈可以通过这个内存地址来调用该类对象。
2.堆被所有的线程共享,JVM中也只有一个堆。
3.堆的特性是不连续,读取速度慢。
-
栈(stack)
1.栈的作用是存放快速执行的任务,基本数据类型的数据,上述的对对象地址的引用。每一个线程都有一个栈区,栈区非常的小,大小只有1M,但是栈区的存取速度快,所以一般用来执行任务。
2.上述每一个线程都有一个栈区,同时呢这些栈区都是独立的,或者说都是私有的,其他栈是不能访问的。
3.栈的单位是帧,栈的规则是"先进后出",就像我们现实生活中的压弹夹,先压进去的后出来。一般来说JVM对栈的操作就是压栈、出栈,以及通过Xss来调节设置栈内存。
-
方法区(method)
1.方法区(静态区),方法区被用来存放所有的不变的元素,比如Class类、static变量(静态变量)、静态方法、常量、成员方法。也因为它存放的都是永远唯一的元素,所以方法区被所有线程共享,其实本质上方法区也是堆。
-
堆、栈、方法区的关系
想要理解堆栈方法区的关系,其实不难,我们只要去代码里走一遭就很好理解了。
public class Test{
public int Num(int x){
x = 10; //修改值
return x; // 返回值 把x的临时值 返回出来
}
public static void main(String[] args){
Test num = new Test(); //实例化对象 需要有一个class模版 这里的模版为Test类 在堆里开辟空间
int a =1 ;
a = num.Num(a); //调用方法 方法储存在堆里的对象空间里 同时在栈中执行(开辟临时方法执行空间)
}
}
上面的代码其实就是一个实例化变量,调用对象内的方法传入实参,在方法里将a从1-->10然后返回,接下来我们来看看具体的实现过程。
首先,在默认执行过程中,classLoader(类加载器)将硬盘中的字节码文件搬运至内存里。
在我们从开始实例化对象时,我们来看看Java虚拟机都做了些什么?
第一步:JVM在方法区里加载了一个Test类模版 ,把信息存在方法区里。
第二步:Java虚拟机在堆内存里为这个新实例化的对象Test分配内存,而在栈中,num持有指向Test类的实例的引用
第三步:完成实例化对象,接下来,我们从常量池里取出数字1的地址将之给a
第四步:接下来我们执行调用num实例里的方法Num(),并传入实参a,此时栈内存内开辟临时方法执行空间,来操作形参x,从常量池中取出10将x=1变为x=10。
第五步:最终return x;将x的值返回出来,这里需要注意,如果不执行return,且使用变量承接,x的改变值将不会传出该方法。
结合这个流程就可以较好的理解前面描述的关于堆、栈、方法区的概念了。