堆内存 和 栈内存的简单理解

看一个例子:

var a =3;
var b = a;
a=1;
console.log(a,b);
var arr1 = [1,2,3,4];
var arr2 = arr1;
arr1.push(5);
console.log(arr2);

 第一个console.log(a,b) 1 3;

第二个console.log(arr2)  [1,2,3,4,5]

这个问题很奇怪。为什么 b的值变成了 a 原来的值,没有随着a的重新赋值而变化,而 arr2却随着 arr1的变化而变化呢?

原因是;JS值分为两种 :原始值引用值

原始值:String,Undefined、Null、Boolean、Number

引用值:Object  Array Function Date RegExp

所以很显然了,a 和 b 是属于Number类型的,即原始值;而 arr1 和 arr2是属于 Array 类型的,即引用值;

原始值存储在 中;

引用值存储在 中;并且 在 栈 中存储了 堆 的地址;如下图所示:

所以,两种值的存储方式不同,导致了问题的发生。

原始类型中:

var a =3; //在栈中 开辟空间存放3 并且名称为a
var b = a; // 在栈中 开辟空间存放复制 a 的值 并且名称为b
a=1; //在栈中 开辟空间存放3 并且名称为a,原来的地址 a 改为默认的地址,这里是默认的1008,如上图所示;
console.log(a,b);

 引用类型中:

var arr1 = [1,2,3,4];//在堆中 开辟空间存放[1,2,3,4]   并在栈中开辟空间存放 指向对中的地址,栈中名称为 arr1
var arr2 = arr1;// 在栈中开辟空间存放 指向对中的地址,栈中名称为 arr2  这里 arr2存放的堆地址 与 arr1的堆地址相同。
arr1.push(5);
console.log(arr2);

 

那么如果arr1重新赋值,arr2 会随之 arr1的赋值而改变吗?

其实是不会的,原因是,在堆中,arr1的存储过程中,需要重新再开辟一个空间来存放 arr1最新的一次赋值,当然arr1在栈中指向堆的引用地址就发生了改变,这个时候,arr2在栈中的引用地址 和 arr1的地址不同。所以,这个时候,arr2 不会随着 arr1的赋值而改变。

再看一个Java中的例子:

Java一维数组的内存解析

这个例子输出结果是null;

如果是基本数据类型

1     @Test
2     void test() {
3         int a = 0;
4         int b = a;
5         a = 2;
6         System.out.println(b);
7                 
8     }

输出结果是0;因为b在栈空间中存的是0,不是地址值;

再看一个对象的内存解析:

Java知识点补充:

  一、栈(Stack ),是指虚拟机栈。虚拟机栈用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、char、short、int、float、  long、double)、对象引用 (reference类型,它不等同于对象本身,是对象在堆内存的首地址)。方法执行完,自动释放。

  •  栈:先进后出
  • 方法中定义的变量都是局部变量,存在于栈空间中

   二、堆(Heap),此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在 Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。

  • 将new出来的结构(比如:数组、对象)加载在对空间中。
  • 补充:对象的属性(非static的)加载在堆空间中

  三、方法区(Method Area),用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

  注意点:编译完源程序以后,生成一个或多个字节码文件。
  我们使用JVM中的类的加载器和解释器对生成的字节码文件进行解释运行。意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析。

参考地址:https://www.cnblogs.com/zhufeng123/p/12263011.html

posted @ 2019-05-15 00:30  啄木鸟伍迪  阅读(889)  评论(0编辑  收藏  举报
//火箭 GenerateContentList();