Java中的堆栈和堆内存

2023-03-07 09:29:31 浏览数 (1)

大家好,我是小面。今天将给大家介绍一下Java中的堆栈和堆内存。

Java数据类型在执行期间存储在两种不同形式的内存中:堆栈和堆。它们通常由运行Java虚拟机(JVM)的底层平台维护。小面从Java软件开发的角度对这两种内存类型提供了一些见解。

Java平台如何工作?

Java程序在Java虚拟机(JVM)提供的平台上运行。该平台是管理器,它提供java应用程序在运行时所需的所有资源。这意味着程序开发人员编写的程序或我们创建的应用程序无法直接访问系统资源(无论是硬件还是软件),除非其运行的平台提供。对于Java,顺序如下:

代码语言:javascript复制
java应用程序 --> JVM --> 操作系统 --> 硬件

JVM层使Java平台独立。其他编程语言,如C/C ,不使用这样的层,因此,它们本身不是独立于平台的,即使它们是可移植的:

代码语言:javascript复制
java应用程序 --> 操作系统 --> 硬件

这两种情况都有很多优点和缺点。由于开发Java语言和平台JVM的人员都是同一组人,因此对程序员便利性的偏见是显而易见的。这导致了巨大的演变;从一种语言开始,今天Java已经成为自己的生态系统。同时,像C/C 这样的编程语言能够直接访问系统资源,从而产生超级快速和高效的程序,从而更接近于核心单元的最佳使用。但两者在软件开发领域都有各自的用途。

对于一般的语言,所有编程语言在编译和执行过程中都有许多相似之处。其中最重要的一个领域是内存管理。无论使用何种语言,内存管理都会对程序的总体效率产生重大影响,因为它有助于管理内存资源,从而提高应用程序的性能。使用的内存越多,程序就越慢。

什么是Java中的运行时内存?

应用程序中的一个常见现象是,每个应用程序都需要一些内存才能以最佳方式工作。该内存由底层平台提供。对于Java,JVM提供它(当然,这是由操作系统授权的)。JVM内存的典型五个部分包括:方法区域、堆、堆栈、PC寄存器和本机内存。

现在让我们关注堆栈和堆部分。内存不像一张白纸,程序员只需记下数据就可以存储数据。相反,内存需要在使用之前进行结构化。堆栈和堆是使用内存时遵循的数据结构。在程序执行期间,根据程序的用途,存储的数据用于各种用途。

JVM决定程序执行期间使用的运行时数据区域。一些数据区域依赖于JVM,这意味着,它们是在JVM启动时创建的,并且在JVM的整个生命周期中继续存在。但是,还有其他数据区域是每个线程创建和销毁的。JVM可以同时执行多个执行线程。这意味着每个线程都有自己的pc(程序计数器)寄存器来维护当前正在执行的指令的位置,以及一个用于保存静态内存分配的堆栈。

什么是Java中的堆栈内存?

堆栈是内存中的一种结构,开发人员在其中存储元素(如一堆书),其方式仅允许从堆栈顶部检索数据,通常称为先进先出(FILO或LIFO)。由于每个线程都维护一个私有的JVM堆栈,因此它用于存储与其静态内存分配相关的变量。我们在代码中声明和使用的特定于方法的原始变量实际上存储在堆栈区域中。此外,对实际存储在堆内存中的对象的引用也存储在堆栈区域中。因此,本地分配的任何内存都存储在堆栈中。

可以使用JVM参数-Xss更改堆栈内存的默认大小。有时,如果分配了太多变量,或者某个方法递归调用自己,堆栈可能会溢出。所有Java程序员都知道的一个常见错误是Java.lang.StackOverFlowError。当堆栈变满时,会弹出此错误。Java中的每个方法调用都会在堆栈中创建一个新块。因此,设计糟糕的递归方法调用很容易耗尽所有堆栈,从而导致溢出错误。

什么是Java中的堆内存

堆是一个内存区域,它在JVM启动时就创建,并一直存在,直到JVM被销毁。与堆栈不同,堆栈是单个线程的属性(因为每个线程都有自己的堆栈),堆实际上是由JVM自身管理的全局存储。此内存在运行时用于为对象分配内存。因此,对象实例化可以是用户定义的类、JDK或其他库类。简而言之,使用新关键字创建的任何对象都存储在堆内存中。JVM运行的所有线程都可以访问堆内存中的对象。访问管理是复杂的,并且使用非常复杂的算法。这就是JVM垃圾收集器发挥作用的地方。

可以使用-Xms和-Xmx JVM参数更改堆的默认大小。随着创建和销毁对象的数量增加,堆的大小也会增加和减少。如果达到其最大限制并尝试进一步分配,它将抛出java.lang.OutOfMemoryError。

Java堆字符串池

非常有趣的是,尽管它是一个类,但对于java.lang.String,从这个类实例化的任何对象都有不同的处理方式。JVM创建者发现,这是Java编程中使用最多的类。因此,应特别注意保持其效率。此外,与原始类型相比,字符串操作总是很慢。因此,魔力必须存在,以便字符串对象的使用与使用原始类型相似,或者在代码中的效率和便利性方面与之接近。因此,为了保持JVM提供的效率,在堆中使用了一个名为StringPool的特殊内存区域。JVM将创建的任何字符串对象存储在StringPool中。与堆中创建的其他对象相比,这提高了性能。

Java堆和堆栈代码示例

为了更好地说明Java中堆和堆栈内存的使用,让我们编写一个简单的程序,并决定哪个分配分配给哪个内存——堆还是堆栈:

代码语言:javascript复制
package project1;
import java.util.Date;
public class Main{
    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;
    }
}

这段Java代码的工作方式如下:

  • 程序启动,JVM将Java Runtime Environment(JRE)类加载到堆中。
  • 遇到main()方法时,将创建堆栈。
  • 局部变量x和y存储在堆栈中。
  • 字符串greet分配在堆的StringPool区域中。
  • Date对象在堆区域中分配,而其引用d存储在堆栈中。

关于Java堆栈和堆内存的最后思考

堆栈和堆是Java程序在代码执行期间使用的两个区域。除了这两个之外,还有其他内存区域,例如方法区域、寄存器、本地区域等等。它们在Java应用程序中都有其特定的用途。但是,从程序员的角度来看,堆栈和堆是JVM的基本方面,必须理解。然而,深入了解所有运行时内存规范始终是一个优势,这将是未来Java编程教程的主题。

今天的分享就到此结束,如果觉得本文不错的还请伙伴们帮忙点赞转发,欢迎持续关注我们!

0 人点赞