View Code
方法是如何执行的,底层内存分配:
1.方法进栈
2.方法中的局部变量,基本里欸行直接保存在栈里,引用类型,变量名保存在栈里,对象保存在堆里(通过new关键字new出的对象),通过地址关联;
3.方法执行完,方法出栈,垃圾回收。
Java中的内存分配
* A:栈(掌握)
* 存储局部变量
局部变量:定义在方法声明上和方法中的变量
* B:堆(掌握)
* 存储new出来的数组或对象
* C:方法区
* 代码
* D:本地方法区
* 和系统相关
* E:寄存器
* 给CPU使用
【Java中内存的分配
栈,堆,方法区(静态区),本地方法区,寄存器
栈: 栈内存中存储的都是局部变量 ? 在方法中定义的变量.
方法执行时,会在栈内存中开辟一个内存空间 (压栈)
方法执行完毕,会被销毁(弹栈)
特点 先进后出 变量的生命周期结束,内存就会被释放
堆: 存储的都是实体 对象 new Object() malloc free
回收
内存泄露 超过java虚拟机分配的内存上限. 程序就会 内存溢出】
1.一维数组的内存
(1)一个数组的内存图解
首先是方法进栈,main方法圧进栈,随后变量进栈,new的对象进入堆,要使用时取堆里的地址值
(2)两个数组的内存图解
会在堆中新建两个个地址空间
(3)数组的初始化静态初始化
2.二维数组的内存
(1)二维数组格式1 int [][] arr = new int[3][2]
在堆中先建立一个一维数组,一维数组的每个索引存的是地址, 默认初始化值是null
3.Java中的参数传递问题
程序一:基本数据类型的值传递,不改变原值,因为调用后就会弹栈,局部变量随之消失
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("a:"+a+",b:"+b);
change(a,b);
System.out.println("a:"+a+",b:"+b);
}
public static void change(int a,int b) {
System.out.println("a:"+a+",b:"+b);
a = b;
b = a + b;
System.out.println("a:"+a+",b:"+b);
}
输出结果: 10 20 10 20
20 40
10 20
main方法进栈,随后change方法进栈
change执行完毕后,弹栈
程序二:引用数据类型的值传递,改变原值,因为即使方法弹栈,但是堆内存数组对象还在,可以通过地址继续访问
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
change(arr);
System.out.println(arr[1]);
}
public static void change(int[] arr) {
for(int x=0; x<arr.length; x++) {
if(arr[x]%2==0) {
arr[x]*=2;
}
}
}
输出 4
同样也是先main进栈,随后change进栈
最后change出栈,但堆内存区的值不会改变
4.对象
(1)一个对象
将磁盘上的文件编译成字节码文件,而在运行时字节码文件进入内存的方法区,首先是Demo1_Car ,虚拟机调用main,main进栈,Car先将Car.class加载入内存,随后通过Car创建对象,在堆里创建对象,并将成员变量赋初值,String的赋值null,int的赋值为0,将对象的地址传入,在通过地址找到对象,对成员变量赋值,调用run方法,run方法进栈,运行完之后弹栈
(2)二个对象
如果没有任何引用指向该对象,那么该对象就会变成垃圾,java中有完善的垃圾回收机制,会在不定时对其进行回收
(3)三个引用两个对象
同两个对象类似,将从c2的地址赋值给c3
(4) 创建对象的步骤
* Student s = new Student();
* 1,Student.class加载进内存
* 2,声明一个Student类型引用s
* 3,在堆内存创建对象,
* 4,给对象中属性默认初始化值
* 5,属性进行显示初始化
* 6,构造方法进栈,对对象中的属性赋值,构造方法弹栈
* 7,将对象的地址值赋值给s
同以前,创建对象后,赋初始值
再根据对属性进行显示初始化,随后虚拟机自动调用构造方法
对象创建完毕,构造方法弹栈