Java中的堆与栈

Java把内存划分成两种:一种是栈内存,一种是堆内存

其实,除了堆和栈之外,还有一部分区域,称为静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。java中将内存的划分,大致如下草图所示:

一、栈内存

存放基本类型的变量,对象的引用和方法调用,遵循先入后出的原则。

1. 栈内存中存放的基本数据类型的变量

java中八种基本数据类型:byte 、short 、int 、long、float 、 double、char、boolean,除了基本数据类型外,其他的为引用数据类型。

在java中如何存放基本数据类型的变量呢?我们通过一个例子来看看。

假设我们同时定义: 
  int a = 3; 
  int b = a; 

这两条语句在编译器中的处理过程:1. 先处理int a = 3;首先它会在栈中创建一个int类型变量为a的空间。

                                                                2. 然后将常数3放入常量区。

                                                                3. 开辟一个变量空间b,将a中的数据复制一份,放入b中。

接着执行一条语句:b = 4;

这时b中原来存放3的数据被删除,在常量区中找到4这个值,将4放入b的变量空间中。

从这个例子中,我们可以看出来:开始时a虽然赋值给了b,它们拥有了相同的数值3,但当b改变时(存放4)时,a的值并没有改变(仍然为3)。

理解这个后,接下来看栈中存放对象的引用这个例子,将这两个例子对比着理解:

2.  栈内存中存放对象的引用

java中的对象,大家都知道,需要通过new关键字来创建。那栈中存放对象的引用,指的是什么呢?其实,这里存放对象的引用,指的是对象的引用变量,也是一个变量,只不过这个变量不是基本数据类型,而是引用数据类型。

关于引用数据类型的具体内容:读者只需知道除了八种基本数据类型之外的,基本上都是引用数据类型,并且,引用数据类型的变量中存放的不是具体的值,而是地址。

通过一个例子来理解,在此使用数组这个引用类型来进行讲解:

int[ ] x = new int[ ] {1,2,3};

int[ ]y = x;

这两条语句在编译器中的处理过程:

1. 首先看第一条语句中"="的左边(int[ ]x),它会在栈内存中创建一个int[ ]的引用类型变量x的空间。

2. 然后看"="的右边(new int[ ]{1,2,3}),首先说明:数组在堆内存中的空间形态是一串连续的地址空间,用来存放数组元素。因为执行new操作,因此在堆内存中开辟一连串连续的空间,存放1,2,3。

3. 最后在栈内存中创建一个int[ ]类型的变量y,并将x中的值复制一份存入y中。(注意x中的值是一个地址,因此y中存放的也是这个地址)如下示意图所示:

从上图可以看出:1. 引用类型的变量x和y是在栈内存中被创建。

                                2. 在堆内存中开辟一块连续的int类型的空间,用于存放数组元素。

                                3. x和y中存放的都是该数组首元素的地址,可以找到该数组。

接着执行一条语句:y[0] = 100;

该语句是改变了数组中第一个元素的数值,这时,x[0]中的数值也不再是1,而是100。

通过上面两个例子,可以对比栈中存放基本数据类型的变量和存放引用数据类型的变量的不同之处

     如果栈中变量空间存储的是基本数据类型:存储的是值,一个变量的值改变,另一个不会跟着改变。

     如果栈中变量空间存储的是引用数据类型:存储的是引用(地址),一个变量地址对应的值改变,另一个也跟着改变。

3栈内存中存放方法的调用

     Java中的代码是在函数体中执行的,每个函数主体都会被放在栈内存中,比如main函数。假如main函数里调用了其他的函数,比如add(),那么在栈里面的的存储就是最底层是main,mian上面是add。栈的运行时后入先出的,所以会执行时会先销毁add,再销毁main。

 

栈的优点和缺点

                                栈的优势是:(1) 栈内存与堆内存相比是非常小的,但存取速度比堆要快,仅次于寄存器。

                                                        (2) 栈数据可以共享。

                                栈的缺点是:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

栈中主要存放一些基本类型的变量(int, short, long, byte, float, double, boolean, char)和对象句柄,也可以存放引用数据类型。栈有一个很重要的特殊性,就是存在栈中的数据可以共享。

 

二、堆内存

存放所有new出来的对象和数组

特此强调,堆内存和数据结构中的堆完全是两码事。

堆内存是区别于栈区、全局数据区和代码区的另一个内存区域。堆允许程序在运行时动态地申请某个大小的内存空间,堆内存实际上指的就是(满足堆内存性质的)优先队列的一种数据结构,第1个元素有最高的优先权。

在上面讲栈内存中已经提到在堆内存中存放数组这种引用数据类型,下面再举一个例子,使读者更加详细的了解到堆内存中存放的数据。

例子:

public People(){
    private name;    //姓名
    private age;     //年龄
    private weight;  //体重
    
  public void nameTest(String name){

        println("我叫"+name);
   }

  public static void main(String[] args){

        People p1 = new People();
               p1.peopleTest("张三");

  }
}

上面这段代码,是创建一个People类,里面有三个属性,一个方法。我们主要是看main函数中的代码。

People p1 = new People();

看这条语句,有人会说,这里的p1是一个对象,是Person类的一个实例。

也有人会说,这里的person并不是真正的对象,而是指向所创建的对象的引用。

到底哪种说法是对的?我们先不急着纠结哪种说法是对的,再看两行代码:

People  p1;

p1 = new People();

这两行代码实现的功能和上面的一行代码是完全一样的。大家都知道,在Java中new是用来在堆上创建对象用的,如果p1是一个对象的话,那么第二行为何还要通过new来创建对象呢?由此可见,p1并不是所创建的对象,而是一个引用,是一个可以指向Person类的对象的引用。真正创建对象的语句是右边的new Person( );

上面说了这么多,其实就是想让大家明白:

                               1. 创建对象是在new出现时才会创建

                               2. "="左边的p1和"="右边new出来的对象并不是存储在一起。p1是在栈内存中,new出来的对象是在堆内存中。

                               3.  p1并不是对象,而是指向对象的引用。p1里面存放一个地址,指向对象。

通过上面这个图,可以看出来,new出来的对象存放在堆内存中,并且在堆内存中开辟一个空间,存放对象的属性和方法。

 

三、堆内存和栈内存的区别:

栈与堆都是Java用来在Ram(内存)中存放数据的地方。

1、内存区域不同、存放数据不同。

堆内存和栈内存在内存区域中有不同的区域。堆允许程序在运行时动态地来申请某个大小的内存空间。栈内存在函数中定义的一些基本类型的变量对象的引用变量都在函数的栈内存中分配。

2、数据结构不同

堆内存实际上指的就是优先队列的一种数据结构,第1个元素有最高的优先权;栈内存实际上就是满足先进后出的性质的数据结构。栈内存是存取速度比堆要快,仅次于寄存器,栈数据可以共享。

3、是否自动释放数据

堆内存中分配的内存需要程序员手动释放,如果不释放,则会一直被占用。而栈内存中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。即:栈是由编译器自动分配和释放,如函数参数、局部变量、临时变量等等。堆是由程序员自己申请、自己释放。否则发生内存泄露。典型为使用new申请的堆内容。

 

以上内容是本人将自己查找的知识点进行整合,并加上自己的理解,并不能保证万无一失。希望读者能够取其精华、弃其糟粕,欢迎评论,共同进步。

 

 

 

 

 

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值