本文仅供学习参考!
相关教程地址:
https://www.cnblogs.com/whgw/archive/2011/09/29/2194997.html
https://www.developer.com/java/stack-heap-java-memory/
https://zhuanlan.zhihu.com/p/529280783
Java 数据类型在执行过程中存储在两种不同形式的内存中:栈和堆。它们通常由运行 Java 虚拟机 (JVM) 的底层平台维护。本文从 Java 软件开发的角度提供了对这两种内存类型的一些见解。
Java 平台如何工作?
Java程序运行在Java虚拟机(JVM)提供的平台上。该平台是提供java应用程序运行时所需的所有资源的管理器。这意味着开发人员编写的程序(或我们创建的应用程序)无法直接访问系统资源(无论是硬件还是软件),除非其运行的平台提供了它。对于 Java,顺序如下:
JVM 层使 Java 平台变得独立。其他编程语言,如 C/C++,不使用这样的层,因此,尽管它们是可移植的,但它们本身并不独立于平台:
这两种情况都有很多优点和缺点。由于 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 或其他库类。简而言之,任何使用new关键字创建的对象都存储在堆内存中。JVM 运行的所有线程都可以访问堆内存中的对象。访问管理很复杂,并且使用非常复杂的算法。这就是 JVM 垃圾收集器发挥作用的地方。
可以使用**-Xms和-Xmx** JVM 参数更改堆的默认大小。随着对象数量的创建和销毁,堆的大小会增加或减少。如果达到其最大限制并尝试进一步分配,则会抛出**java.lang.OutOfMemoryError **。
Java堆字符串池
值得注意的是,尽管它是一个类,但对于java.lang.String,从该类实例化的任何对象的处理方式都不同。JVM 创建者发现这是 Java 编程中最常用的类。因此,应特别注意保持其效率。此外,与原始类型相比,字符串操作总是很慢。因此,魔法必须存在,以便字符串对象的使用与使用基本类型类似或接近它在代码中的效率和便利性。因此,为了保持 JVM 提供的效率,使用了堆内称为StringPool的特殊内存区域。创建的任何字符串对象都存储在StringPool中由 JVM 执行。与堆中创建的其他对象相比,这提高了性能。
Java 堆和堆栈代码示例
为了更好地说明 Java 中堆和栈内存的使用,让我们编写一个简单的程序并决定哪个分配分配给哪个内存 - 堆还是栈:
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 运行时环境 (JRE) 类加载到堆中。
- 当遇到**main()**方法时,就会创建一个堆栈。
- 局部变量x和y存储在堆栈中。
- 字符串greet分配在堆的StringPool区域中。
- Date对象分配在堆区域中,而其引用d存储在堆栈中**。**
END
栈和堆是Java程序在代码执行过程中使用的两个区域。除了这两个之外,还有其他内存区域,例如方法区、寄存器、本机区等。每个在 Java 应用程序中都有其特定的用途。但是,从开发者的角度来看,栈和堆是必须了解的 JVM 的基本方面。然而,对所有运行时内存规范的透彻理解始终是一个优势,并且将成为未来 Java 编程教程的主题。