堆和栈的概念和区别

本文深入探讨了JVM内存模型,详细解释了堆内存和栈内存的区别与特性,包括它们的存储方式、生命周期以及更新速度。并通过实例展示了字符串在堆和栈中的存储过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • JVM虚拟机

Java程序在运行时都要开辟空间,任何软件在运行时都要在内存中开辟空间,Java虚拟机运行时也是要开辟空间的。JVM运行时在内存中开辟一片内存区域,启动时在自己的内存区域中进行更细致的划分,因为虚拟机中每一片内存处理的方式都不同,所以要单独进行管理。

JVM内存的划分有五片:

       1.   寄存器;

       2.   本地方法区;

       3.   方法区;

       4.   栈内存;

       5.   堆内存。

  • 堆内存和栈内存的概念

1. 堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。
 

2.栈内存: 栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。

例:https://blog.youkuaiyun.com/pt666/article/details/70876410/

  • 堆和栈的区别

            1.栈内存存储的是局部变量而堆内存存储的是实体;

            2.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;

            3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。

            4.栈(stack):是一个先进后出的数据结构,先分配的内存必定先释放,通常用于保存方法(函数)中的参数,局部变                                          量。在java中,所有基本类型和引用类型都是在栈中存储的。栈中数据的生存空间一般在当前的                                                    scopes(就是由{...}括起来的区域)。一般是由系统自动分配,存放函数的参数值,局部变量,自动清除。

               堆(heap):1). 是一个可动态申请的内存空间(其记录空闲内存空间的链表由操作系统维护),所谓的动态内存,是                                             其中的内存在不需要时就可以回收,以分配给新的内存请求,其内存中的数据是无序的,即先分配的                                             和后分配的内存并没有什么必然的位置关系,释放时也可以先后顺序。

                                     2). 在Java中,使用new XXX()构造出来的对象都在堆中存储,当垃圾回收器检测到某对象未被引用,则                                            自动销毁该对象。所以,理论上说java中对象的生存空间是没有限制,只要有引用类型指向它,则它                                               可以在任意地方被使用。
         

  • 堆和栈的优缺点:

堆:  JAVA的堆是一个运行时的数据区,堆的优势是可以动态的分配内存大小,生存期也不必事先告诉编译器,因为他是在运行时动态        的分配内存的,JAVA的垃圾回收器会自动回收走这些不用的数据.但缺点是,由于要在运行时动态分配内存,存取速度较慢.

栈: 栈的优势是存取速度比堆快,仅次于寄存器,栈数据可以共享.但缺点是,存在栈中的数据大小和生命周期必须是确定的,缺乏灵活       性.栈中一般存放基本类型(int, short, long, byte, float, double, boolean, char)的变量和对象.

栈有一个很重要的特殊性:存在栈中的数据可以共享。比如下面我们定义:

http://www.cnblogs.com/iyangyuan/p/4631696.html

 

String s =new String()分析堆与栈,是先定义S,还是先new string()
1. String str1 = "abc"; 
    System.out.println(str1 == "abc");

步骤: 
1) 栈中开辟一块空间存放引用str1;
2) String池中开辟一块空间,存放String常量"abc"; 
3) 引用str1指向池中String常量"abc";
4) str1所指代的地址即常量"abc"所在地址,输出为true;

 

2. String str2 = new String("abc"); 
    System.out.println(str2 == "abc");

步骤: 
1) 栈中开辟一块空间存放引用str2; 
2) 堆中开辟一块空间存放一个新建的String对象"abc"; 
3) 引用str2指向堆中的新建的String对象"abc";
4) str2所指代的对象地址为堆中地址,而常量"abc"地址在池中,输出为false;

 

3. String str3 = new String("abc"); 
    System.out.println(str3 == str2);

步骤: 
1) 栈中开辟一块空间存放引用str3;
2) 堆中开辟一块新空间存放另外一个(不同于str2所指)新建的String对象; 
3) 引用str3指向另外新建的那个String对象 ;
4) str3和str2指向堆中不同的String对象,地址也不相同,输出为false;

 

4. String str4 = "a" + "b"; 
    System.out.println(str4 == "ab");

步骤: 
1) 栈中开辟一块空间存放引用str4; 
2) 根据编译器合并已知量的优化功能,池中开辟一块空间,存放合并后的String常量"ab"; 
3) 引用str4指向池中常量"ab";
4) str4所指即池中常量"ab",输出为true;

 

5. final String s = "a"; //注意:这里s用final修饰,相当于一个常量
    String str5 = s + "b"; 
    System.out.println(str5 == "ab");

步骤: 
同四

 

6. String s1 = "a"; 
    String s2 = "b"; 
    String str6 = s1 + s2; 
    System.out.println(str6 == "ab");

步骤: 
1) 栈中开辟一块中间存放引用s1,s1指向池中String常量"a", 
2) 栈中开辟一块中间存放引用s2,s2指向池中String常量"b", 
3) 栈中开辟一块中间存放引用str5, 
4) s1 + s2通过StringBuilder的最后一步toString()方法还原一个新的String对象"ab",因此堆中开辟一块空间存放此对象, 
5) 引用str6指向堆中(s1 + s2)所还原的新String对象, 
6) str6指向的对象在堆中,而常量"ab"在池中,输出为false

 

7. String str7 = "abc".substring(0, 2);   
步骤: 
1) 栈中开辟一块空间存放引用str7, 
2) substring()方法还原一个新的String对象"ab"(不同于str6所指),堆中开辟一块空间存放此对象,
3) 引用str7指向堆中的新String对象,

 

8. String str8 = "abc".toUpperCase(); 
步骤: 
1) 栈中开辟一块空间存放引用str8, 
2) toUpperCase()方法还原一个新的String对象"ABC",池中并未开辟新的空间存放String常量"ABC", 
3) 引用str8指向堆中的新String对象

 

9.String s="abc"; 

   String s1=s; 

   System.out.println(s1=="abc"); 

   s=s+"hello"; 

   System.out.println(s1=="abc"); 

   System.out.println(s=="abc");

步骤:

1)栈中开辟一块空间存放s;

2)Sting池中开辟一块空间用于存放"abc",栈中开辟一块空间存放变量s1;

3)系统输出true,在堆中开辟一块空间用于存放"abchello";

4)引用s指向堆中的"abchello";

5)系统输出true,然后输出false;

 

 

 

 

 

 

JVM的内存模型

栈内存详解

栈内存是一个先进后出的结构。栈内存又可以称为线程内存,即一个线程会开辟一个栈内存。

栈帧:栈帧是属于虚拟机栈的一部分,栈帧里存储了方法的入口,方法的参数,局部变量,返回地址等。栈顶的栈帧代表了当前正在执行的方法,每一个栈帧都又自己的操作栈,局部变量表等,大概5块数据区域

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值