这篇文章主要介绍“Java中的堆和栈是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java中的堆和栈是什么”文章能帮助大家解决问题。
Java程序运行在Java Virtual Machine (JVM)中,JVM提供了Java应用程序在运行时所需要的任何资源的管理器。这就意味着开发者写的应用程序或者创建的应用程序没有能力去直接获取系统资源(不管是硬件还是软件),除非JVM能提供给这些资源。所以在Java中,程序运行顺序如下图:
JVM层使得Java平台能够独立运行,其他编程语言,例如C/C++没有使用类似JVM层的东西,因此它们不是跨平台的语言,即使它们是可移植的语言。它们就像下图一样:
这两种形式有优点也有缺点,Java已经有了自己的生态系统。与此同时,像C/C++这样的编程语言能够直接访问系统资源,从而更有利于优化核心单元的使用,从而产生超级快速和高效的程序。但两者在软件开发领域都有各自的用途。
所有编程语言在编译和执行过程中都有许多相似之处。其中最重要的一点就是内存管理,无论使用哪种语言,内存管理对程序的整体效率都有重要影响,因为管理好内存资源,从而才能管理好应用程序性能。
应用程序之间的一个常见现象是,每个应用程序都需要一些内存才能以最佳方式工作,该内存由底层平台提供。在Java中,JVM提供了这些内存资源(当然需要操作系统授权)。Java中,JVM内存主要分为5个部分分别为:方法区、堆、栈、PC寄存器和本地方法区。
本文主要关注堆和栈。内存不像一张白纸,程序员只需要草草记下就可以存储数据,在使用内存之前,需要对其进行结构化。栈和堆是使用内存时遵循的数据结构,在程序执行期间,存储的数据用于各种目的,这取决于程序的目的是什么。
JVM决定程序执行期间使用的运行时数据区域。有些数据区域是依赖于JVM的,这意味着它们是在JVM启动时创建的,并在JVM的整个生命周期中持续存在。但是,每个线程都创建和销毁其他数据区域。JVM可以同时执行多个执行线程,这意味着每个线程都有自己的pc(Program Counter,程序计数器)来维护正在执行的当前指令的位置,还有一个栈帧来保存静态内存分配。
栈是内存中的一种结构,开发人员在其中存储元素,其方式允许只从栈顶检索数据——通常称为先入后出(FILO或LIFO)。因为每个线程都维护一个私有的JVM栈,它被用来存储与它们的静态内存分配相关的变量。特定于我们在代码中声明和使用的方法的原语变量实际上存储在栈区域中。另外,对实际存储在堆内存中的对象的引用也存储在堆栈区域中。因此,任何本地分配的内存都存储在堆栈中。
堆栈内存的默认大小可以使用JVM参数-Xss来更改。有时,如果分配了太多变量或方法递归调用自身,则堆栈可能溢出。所有Java程序员都知道的一个常见错误是Java.lang.stackoverflowerror
,当栈内存不足时提示该错误。Java中的每个方法调用都会在栈中分配一块内存,因此,设计糟糕的递归方法调用很容易占用所有栈内存,导致栈内存溢出错误。
堆是JVM一启动就创建的内存区域,它会一直存在,直到JVM被销毁。与栈不同的是,栈是单个线程的属性(因为每个线程都有自己的栈),堆实际上是由JVM本身管理的全局内存,此内存在运行时用于为对象分配内存。因此,对象的实例化可以是用户定义的类、JDK或其他库类。简而言之,使用new
关键字创建的任何对象都存储在堆内存中。堆内存中的对象可被JVM运行的所有线程访问。访问管理非常复杂,使用了非常复杂的算法,这就是JVM垃圾收集器发挥作用的地方。
堆的默认大小可以使用JVM参数-Xms
和-Xmx
来更改。随着对象的创建和销毁,堆的大小也会增加或减少,如果达到最大内存限制后并尝试进一步分配内存,则抛出java.lang.OutOfMemoryError
。
Java.lang.String
类是Java中使用最多的类,因此,应该特别注意它的效率问题。与基本数据类型相比,字符串的操作效率总是很慢,所以,必须采用某种方式使得字符串对象操作的效率和便利性方面类似或者接近于基本数据类型,为了达到这个目的就在堆中分配了一块特殊内存区域(StringPool),创建的任何字符串对象都由JVM存储在StringPool中。与堆中创建的其他对象相比,这提高了性能。
为了更好地说明在Java中堆和栈内存的使用,让我们写一个简单的程序,并决定哪个分配分配到哪个内存——堆或栈:
public class HeapAndStackTest { public static void main(String[] args) { int x=10; int y=20; String greet = "Hello"; Date d = new Date(); diff(x, y); } public static int diff(int x1, int x2) { return x2-x1; } }
这段代码运行方式如下:
程序启动,JVM将Java运行时环境(JRE)类加载到堆中。
在遇到main()
方法时,会创建一个栈帧。
局部变量x
和y
存储在栈中。
字符串greet
分配在堆的StringPool区域中。
Date
对象分配在堆区,而它的引用d
存储在栈中。
关于“Java中的堆和栈是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。