Java的内存分配理解
2020-05-30 本文已影响0人
Aunero
本篇文章为本人学习笔记,如有错误,希望指正。
Java 程序在运行时,需要在内存中分配空间。
为了提高运算效率,就对空间进行了不同区域的划分每一片区域都有特定的处理数据方式和内存管理方式。
区域名称 | 作用 |
---|---|
栈内存 | 方法运行时,进入的内存,局部变量都存放于这块内存当中 |
堆内存 | new出来的内容都会进入堆内存,并且会存在地址值 |
方法区 | 字节码文件(.class文件)加载时进入的内存 |
本地方法栈 | 调用操作系统相关资源 |
寄存器 | 给CPU使用 |
- 注意:
- JDK7 : 方法区 ( 永久代 ) 在堆内存的
- JDK8 : 方法区成为了一块独立的内存空间 ( 元空间 )
我们通常直接以 【类型 变量名 = 常量;】定义出来的变量都是在栈内存中。
1. 数组中的内存分配
1.1 单个数组
如图所示,数组变量的声明都在栈中,但是它的地址和对应值都再堆内存中,并且每个格子都有索引和值。
1.2 多个数组
以此类推,两个不同的数组分配了两个空间来存放索引和对应值。
1.3 多个数组指向相同内存
要注意的是,如果存在A,B数组,且数组A被赋值给数组B,那么两个数组将在堆中将共用一个内存空间。
2.方法中的内存分配
- 方法没有被调用的时候,都在方法区中的字节码文件(.class)中存储;
- 方法被调用的时候,需要进入到栈内存中运行。
- 栈就像弹夹,最先压入的子弹,最后才打出。
记忆:栈 —— 先进后出。
- 如图所示,我们在定义一个方法并在main方法里调用时,栈内存和方法区是这样分配的。
3. 方法参数传递的内存分配
3.1 方法参数传递基本类型
public class ArgsDemo01 {
public static void main(String[] args) {
int number = 100;
System.out.println("调用change方法前:" + number);
change(number);
System.out.println("调用change方法后:" + number);
}
public static void change(int number) {
number = 200;
}
}
运行结果:
调用change方法前:100
调用change方法后:100
- 结论:
基本数据类型的参数,形式参数的改变,不影响实际参数。 - 结论依据:
每个方法在栈内存中,都会有独立的栈空间,方法运行结束后就会弹栈消失。
3.1 方法参数传递引用类型
public class ArgsDemo02 {
public static void main(String[] args) {
int[] arr = {10, 20, 30};
System.out.println("调用change方法前:" + arr[1]);
change(arr);
System.out.println("调用change方法后:" + arr[1]);
}
public static void change(int[] arr) {
arr[1] = 200;
}
}
运行结果:
调用change方法前:20
调用change方法后:200
- 结论:
对于引用类型的参数,形式参数的改变,影响实际参数的值。 -
结论依据:
引用数据类型的传参,传入的是地址值,内存中会造成两个引用指向同一个内存的效果,所以即使方法弹栈,堆内存中的数据也已经是改变后的结果。
4. 对象中的内存分配
4.1 单个对象
- 成员变量使用过程
- 成员方法调用过程
4.2 多个对象
- 成员变量使用过程
- 成员方法调用过程
总结:多个对象在堆内存中,都有不同的内存划分,成员变量存储在各自的内存区域中,成员方法多个对象共用的一份。
4.3 多个对象指向相同内存
总结: 当多个对象的引用指向同一个内存空间(变量所记录的地址值是一样的)
只要有任何一个对象修改了内存中的数据,随后,无论使用哪一个对象进行数据获取,都是修改后的数据。
5. this关键字的内存分配
-
this代表当前调用方法的引用,哪个对象调用的方法,this就代表哪一个对象