关于java数组的内存分配,顺便提一下java变量的内存分布

关于数组,我们首先要知道的是,他是引用数据类型,数组是存储同一种数据类型多个元素的容器。数组既可以存储基本数据类型,也可以存储引用数据类型。数组有两种初始化方式,动态初始化和静态初始化.以下通过介绍两种初始化方式来介绍内存的分配.

在介绍内存分配前,首先要对内存有一定的了解:

内存,简单说就是存放正在运行的程序,我们知道,java程序运行的载体是JVM,运行环境是JRE,内存分配给JVM空间执行程序,然后JVM又把内存划分了几个板块,分别是:

栈内存:这个内存是动态的,我们可以在栈内存中看到程序的执行流程(包括方法的执行和死亡),当有方法被调用,就会有方法进入栈内存中.注意,因为栈的特性,方法执行流程是先进后出;同时,栈内存也存放局部变量,使用完毕就会被垃圾回收.

堆内存:这个里面只保存new出来的东西,其本质是对象的实体.比如,你创建了一个数组对象A------>int[] A = new int[5];真正的实体不是左边的A,真正对象的实体是new出来的东西.

关于堆中的元素(new出的对象)的特点:

A.每一个对象都有一个唯一的地址值

B.每一个对象的数据都有默认值,系统根据数据类型给予

            整型:0
            浮点型:0.0
            字符型:'\u0000'
            布尔型:false
            引用数据类型:null

C.堆中的数据使用完毕不会立即回收,在垃圾回收机制空闲的时候回收

方法区:保存字节码文件,也就是.class文件.还有就是常量池.

本地方法区:用来存储java代码和Windows系统交互的方法.

寄存器:跟cpu相关,这里不做过多介绍.

动态初始化内存分配

上图:

一个数组的内存图

讲一下这张图,首先左边的代码到内存后,先到了方法区,当执行到main方法时,main方法从上到下压进栈,给main方法分配一定的空间.接着,我们new一个int类型名字是arr的数组对象.那么,堆内存中会分配一块空间,来初始化这个对象,并有唯一的一个地址值对应这个对象,在栈内存中,会在main方法里分配一块空间,存放数组名 arr,以及new出对象的堆内存地址.

在进行赋值时,比如 arr[0] = 100,赋值过程如下:

在栈内存中通过arr这个数组名,得到一个地址,我们拿着这个地址到堆内存中,找这个地址对应的内存块,根据索引0,找到这块空间,把默认值替换掉.

两个数组内存分配图

我们可以看到每个new出来的对象地址是不同的,这也就解释了下面的代码:

public class TestDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] A1 = new int[2];
		A1[0]=10;
		System.out.println("A1的地址是0"+A1);
		System.out.println("现在A1的值是:"+A1[0]);
		int[] A2 = A1;     //A1的地址传给了A2
		A2[0] =20;         //给A2[0]赋值
		System.out.println("A1的地址是0"+A1);
		System.out.println("A2的地址是0"+A2);
		System.out.println("现在A1的值是:"+A1[0]+"\tA2的值是:"+A2[0]);

	}

}

运行结果:

A1的地址是0[I@1d7fbfb
现在A1的值是:10
A1的地址是0[I@1d7fbfb
A2的地址是0[I@1d7fbfb
现在A1的值是:20	A2的值是:20

静态初始化内存分配:

关于静态初始化内存的分配,就是就是通过栈内存中arr对应的地址,到堆内存中,根据数组索引,把数组的默认值改掉.

下面说一个思想,关于数组反转

先上图:

下面是代码实现:

public class TestDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] a = { 1, 2, 3, 4, 5, 6 };
		int temp;
		//联动for循环
		for (int star = 0, end = a.length - 1; star <= end; star++, end--) {
			temp = a[star];
			a[star] = a[end];
			a[end] = temp;
		}
		System.out.print("arry[");    //优美的输出数组的内容
		for (int i = 0; i < a.length; i++) {
			if (i == a.length - 1) {
				System.out.println(a[i] + "]");
			} else {
				System.out.print(a[i] + ", ");
			}
		}

	}

}

最后补充一个变量的内存分布吧:

这里用到了常量池,在定义变量时,栈内存里存的是常量池中常量对应的地址,对于int b = a,这样的赋值,只是把b指向跟a相同的常量地址,在改变b的常量时,改变的时b指向的常量池的地址,a不会受到改变.

猜你喜欢

转载自blog.csdn.net/znmdwzy/article/details/81274821