最近在准备面试的东西,特意看了一下堆 栈 方法区的概念。特此整理了一下。
堆 栈 方法区 存储哪些数据
- 堆:线程共享,存储对象以及数组(数组也是对象的一种 new方式创建出来的),同时由于对象内存是动态分配的,对象在超过生命周期及空指针的时候会被gc垃圾回收机制回收,所以效率较慢。
- 栈:用于存储基本数据类型以及对象的引用类型(这里指的基础类型是指不为static修饰的变量,如成员变量 局部变量等.)同时栈存在着先进后出的特点与队列需要区分开(队列是2个口子,一边进 一边出,所以是先进先出).同时栈中存在着3个部分:基础数据区(可以理解为存储基础数据类型的),执行环境上下文(估计是用来存引用类型的),操作指令区(存储操作指令的)
- 方法区:用于存储类即static变量及方法的(因为static修饰的变量属于类).这里的方法 成员方法与静态方法都存在方法区里面。java编译为class文件的过程 就可以理解为将类放入方法区的过程.
引用网上资料的一张图:https://blog.csdn.net/qq_26805137/article/details/52996910
结合具体例子看下:原文地址:https://blog.csdn.net/yitian_66/article/details/79712493
public class AppMain //运行时, jvm 把appmain的信息都放入方法区 (类-》方法区)
{
public static void main(String[] args) //main 方法本身放入方法区。 (方法-》方法区,arrgs局部变量-》栈)
{
Sample test1 = new Sample( " 测试1 " ); //test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面
Sample test2 = new Sample( " 测试2 " );
test1.printName();
test2.printName();
}
}
public class Sample //运行时, jvm 把appmain的信息都放入方法区
{
private String name; //new Sample实例后, name 引用放入栈区里, name 对象放入堆里
public Sample(String name)
{
this .name = name;
}
public void printName() //print方法本身放入 方法区里。
{
System.out.println(name);
}
}
从上面的例子可以进一步加深对堆 栈 方法区在数据结构存放位置的理解。
另外再整体理一下整个代码从开始到最后涉及到内存操作的理解:
- 运行AppMain.java类文件,先通过编译器将java文件编译成class文件,将AppMain类信息加载到方法区中,这里这个类没有static变量所以做得就这么多。然后编译器通过classpath地址找到AppMain.class文件。
- 找到这个AppMain类存储在栈中的main方法,然后创建Sample类,这个时候
Sample在方法区中还没有被加载,那么jvm虚拟机就会将Sample类加载到方法区中,同时需要创建实例和引用类型,所以会分别将引用类型+该类中的方法及成员变量,局部变量放到栈中,引用类型指向存在在堆中的实例。 - 通过引用类型 test1找到了 寄放在堆中的实例,通过test1.printName()调用存放在栈中的方法,同时将栈中的基础数据类型 也就是成员变量name设置一下。自此应该就完成了类加载到方法调用的整个过程。
总结
总的来看,在长时间写业务代码的过程,对于java基础原理等概念的理解不能放松,万一公司爆炸了也省得到了面试市场一问就爆炸的情况。这种情况在之前实习跳槽的时候就知道了,但平时还是太懒惰了。 另外看到这篇文章的同学如果发现文章有错误之处,欢迎指出,我会及时更改.以免误导后面的同学。