Java中堆和栈的概念和区别

 更新时间:2020年06月17日 10:25:55   作者:JavaJIAMIN  
Java的堆是一个运行时数据区,类的对象从堆中分配空间。栈中主要存放一些基本数据类型的变量(byte,short,int,long,float,double,boolean,char)和对象的引用,这篇文章给大家详细介绍java 堆和栈的概念和区别,一起看看吧

当一个人开始学习Java或者其他编程语言的时候,会接触到堆和栈,由于一开始没有明确清晰的说明解释,很多人会产生很多疑问,什么是堆,什么是栈,堆和栈有什么区别?更糟糕的是,Java中存在栈这样一个后进先出(Last In First Out)的顺序的数据结构,这就是java.util.Stack。这种情况下,不免让很多人更加费解前面的问题。事实上,堆和栈都是内存中的一部分,有着不同的作用,而且一个程序需要在这片区域上分配内存。众所周知,所有的Java程序都运行在JVM虚拟机内部,我们这里介绍的自然是JVM(虚拟)内存中的堆和栈。

  1. Java的堆是一个运行时数据区,类的对象从堆中分配空间。这些对象通过new等指令建立,通过垃圾回收器来销毁。2. 堆的优势是可以动态地分配内存空间,需要多少内存空间不必事先告诉编译器,因为它是在运行时动态分配的。但缺点是,由于需要在运行时动态分配内存,所以存取速度较慢。 

1. 栈中主要存放一些基本数据类型的变量(byte,short,int,long,float,double,boolean,char)和对象的引用。2. 栈的优势是,存取速度比堆快,栈数据可以共享。但缺点是,存放在栈中的数据占用多少内存空间需要在编译时确定下来,缺乏灵活性。

举例说明栈数据可以共享

String 可以用以下两种方式来创建:

第一种使用new来创建的对象,它存放在堆中。每调用一次就创建一个新的对象。 

第二种是先在栈中创建对象的引用str2,然后查找栈中有没有存放“abc”,如果没有,则将“abc”存放进栈,并将str2指向“abc”,如果已经有“abc”, 则直接将str2指向“abc”。

下面用代码说明上面的理论:

public static void main(String[] args) {
        String str1 = new String("abc");
        String str2 = new String("abc");
        System.out.println(str1 == str2);
    }

输出结果为:false

public static void main(String[] args) {
        String str1 = "abc";
        String str2 = "abc";
        System.out.println(str1 == str2);
    }

输出结果为:true

因此,用第二种方式创建多个“abc”字符串,在内存中其实只存在一个对象而已。这种写法有利于节省内存空间。同时还可以提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否创建新对象。

String str1 = new String("abc");
String str2 = "abc";

附录:Java中的堆和栈的区别

java中堆和栈的区别自然是面试中的常见问题,下面几点就是其具体的区别

各司其职

最主要的区别就是栈内存用来存储局部变量和方法调用。
而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。

独有还是共享

栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。
而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。

异常错误 

如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError。
而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError。

空间大小

栈的内存要远远小于堆内存,如果你使用递归的话,那么你的栈很快就会充满。如果递归没有及时跳出,很可能发生StackOverFlowError问题。
你可以通过-Xss选项设置栈内存的大小。-Xms选项可以设置堆的开始时的大小,-Xmx选项可以设置堆的最大值。

这就是Java中堆和栈的区别。理解好这个问题的话,可以对你解决开发中的问题,分析堆内存和栈内存使用,甚至性能调优都有帮助。

查看默认值(Updated)

查看堆的默认值,使用下面的代码,其中InitialHeapSize为最开始的堆的大小,MaxHeapSize为堆的最大值。

13:17 $ java -XX:+PrintFlagsFinal -version | grep HeapSize
 uintx ErgoHeapSizeLimit    = 0     {product}
 uintx HeapSizePerGCThread   = 87241520    {product}
 uintx InitialHeapSize    := 134217728    {product}
 uintx LargePageHeapSizeThreshold  = 134217728    {product}
 uintx MaxHeapSize    := 2147483648    {product}
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

查看栈的默认值,其中ThreadStackSize为栈内存的大小。

13:21 $ java -XX:+PrintFlagsFinal -version | grep ThreadStackSize
 intx CompilerThreadStackSize   = 0     {pd product}
 intx ThreadStackSize    = 1024    {pd product}
 intx VMThreadStackSize    = 1024    {pd product}
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)

总结

到此这篇关于Java中堆和栈的概念和区别的文章就介绍到这了,更多相关java 堆和栈的概念和区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中Buffer缓冲区的ByteBuffer类详解

    Java中Buffer缓冲区的ByteBuffer类详解

    这篇文章主要介绍了Java中Buffer缓冲区的ByteBuffer类详解,ByteBuffer类是Java NIO库中的一个重要类,用于处理字节数据,它提供了一种灵活的方式来读取、写入和操作字节数据,ByteBuffer类是一个抽象类,可以通过静态方法创建不同类型的ByteBuffer对象,需要的朋友可以参考下
    2023-10-10
  • Java list乱序的实现三种方法

    Java list乱序的实现三种方法

    本文主要介绍了Java list乱序的实现三种方法,包含Collections.shuffle()方法,random和Stream API这三种,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Spring详细讲解事务失效的场景

    Spring详细讲解事务失效的场景

    实际项目开发中,如果涉及到多张表操作时,为了保证业务数据的一致性,大家一般都会采用事务机制,好多小伙伴可能只是简单了解一下,遇到事务失效的情况,便会无从下手,下面这篇文章主要给大家介绍了关于Spring事务失效场景的相关资料,需要的朋友可以参考下
    2022-07-07
  • Java三种方法将List转换为Map的实例

    Java三种方法将List转换为Map的实例

    今天小编就为大家分享一篇关于Java三种方法将List转换为Map的实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-10-10
  • 详解Java修饰符

    详解Java修饰符

    Java语言提供了很多修饰符,主要分为以下两类:访问修饰符;非访问修饰符。修饰符用来定义类、方法或者变量,通常放在语句的最前端。我们通过下面的例子来说明,下面就跟小编一起来看下吧
    2016-12-12
  • Java经典设计模式之装饰器模式解析

    Java经典设计模式之装饰器模式解析

    这篇文章主要介绍了Java经典设计模式之装饰器模式解析,装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承,指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,需要的朋友可以参考下
    2023-08-08
  • SpringCloud使用Feign实现动态路由操作

    SpringCloud使用Feign实现动态路由操作

    这篇文章主要介绍了SpringCloud使用Feign实现动态路由操作,文章围绕主题展开详细的内容介绍具有一定的参考价值,需要的小伙伴可以参考一下
    2022-06-06
  • 解析电子邮件的基本概念及JavaMail API邮件功能使用

    解析电子邮件的基本概念及JavaMail API邮件功能使用

    这篇文章主要介绍了电子邮件的基本概念及JavaMail API邮件功能使用,包括用Java来发送邮件的示例,需要的朋友可以参考下
    2016-02-02
  • java启动如何设置JAR包内存大小

    java启动如何设置JAR包内存大小

    这篇文章主要介绍了java启动如何设置JAR包内存大小问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • Java集合中的LinkedHashMap使用解析

    Java集合中的LinkedHashMap使用解析

    这篇文章主要介绍了Java集合中的LinkedHashMap使用解析,LinkedHashMap是继承于HashMap的,所以它的很多属性和方法都是HashMap中的,那么它是怎么实现有序存储的呢,需要的朋友可以参考下
    2023-12-12

最新评论