在java中内存分为两种,一种是栈(PC、Stack、Native Stack)内存,另一种是堆(堆、方法区)内存,堆和栈都是Java中用来在RAM中存放数据的地方,如下图所示:
栈(Stack)
Java中一个线程一个栈区,每一个栈中的元素都是私有的,不被其他栈所访问。
栈有后进先出的特点,栈中的数据大小与生存期都是确定的,缺乏灵活性,但是,存取速度比堆要快,仅次于CPU中的寄存器,另外栈中的数据是共享的。
在Java中所有的基本数据类型和引用变量(对象引用)都在栈中存储,栈中数据的生存空间一般在当前的scopes内,也就是“{}”的部分,比如:函数的参数值,局部变量等,是自动清除的。
基本数据类型:Java中的基本数据类型包括8种,分别是byte、short、int、long、float、double、boolean、char;
通过以下例子说明:
int m=2; int n=2;
当定义的是基本数据类型时,这些字面值的数据,大小和生命周期皆可知。
编译器首先处理 int m=2;,先是在栈中创建一个变量为m的引用,然后查找有没有值为2的地址,没有则开辟一个新的存放字面值为2的地址,然后将m指向2的地址。
接着处理 int n=2,在创建完n的引用变量之后,由于存在2这个数值,则将n指向2的地址,这样会出现(m==n)为true的情况,也就是m和n指向同一个地址。
类对象的引用类型:与字面值的引用不同,当同时指向一个地址的类对象的引用,如果该对象的内部状态发生改变,则另一个对象引用变量也发生变化。
与之相反,当定义完m之后,修改m的值,即m=3,那么n不会发生改变,依然等于2。
堆(Heap)
Java中只有一个堆,被所有线程共享,堆中的数据没有先后顺序(逻辑上连续就好)。
堆中的数据不需要事先告诉编译器它的生存期,可以动态的分配内存的大小(动态的申请内存空间),也就是这样导致了存取速度慢。
不再使用的数据由Java中的垃圾回收机制自动回收。
在Java中由new创建出来的对象都是在堆中的,当垃圾回收机制检测到某对象未被引用时,则自动销毁该对象。
包装类数据:Java中的包装数据类型包括Byte、Short、Integer、Long、Float、Double、Boolean、Character,这些数据类型都是存放在堆中的,Java中通过new( ) 操作显示的告诉编译器,当运行时根据需要动态创建,缺点就是速度慢。
String类型:是一种特殊的包装类,也是通过new( )操作动态的创建数据,比如:String s1=new String(“abcd”);
方法区
又叫静态区,跟堆一样,被所有的线程共享;方法区包含所有的class和static变量;方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
堆和栈的区别
1.存放内容不同
栈内存:用来存放在方法中定义的一些基本数据类型的变量和引用类型的变量。
堆内存:用来存放运行时创建的对象。
2.生命周期不同
栈的生命周期与线程相同,随线程而生,随线程而亡,是线程私有的。
堆的生命周期与JVM相同,JVM启动时创建,JVM停止时销毁,是线程共享的。
3.内存回收管理不同
栈随线程而生,随线程而亡,每个方法被执行的时候都会创建一个栈帧,栈帧随着方法的进入和退出做入栈和出栈操作, 实现了自动内存清理。
堆是线程共享的内存区域,没有确定的销毁时间。
因此,内存回收主要集中于堆中,在堆中分配的内存由垃圾收集器来管理回收。
4.存取速度不同
栈的存取速度较快,仅次于寄存器。但栈的数据大小与生存期必须是确定的,缺乏灵活性。
堆在运行时动态分配内存,生存期不用提前告诉编译器,这也导致了堆的存取速度较慢。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》