为了更高效的运行应用程序,JVM 抉择将内存划分为栈空间和堆空间。 每当咱们申明新变量和对象、调用新办法、申明 String 或执行相似操作时,JVM 都会在栈或堆空间外面操作指定内存。

在这篇文章外面,咱们将简要介绍 JVM 的内存模型以及它们的次要性能,而后咱们将介绍它们是如何存储在内存外面,以及会在哪里应用到它们。最初,咱们将分几个维度总结它们之间的次要区别。

1. 栈空间


JVM 中的栈空间用于动态内存调配和线程的执行。 它蕴含办法的原始值以及对象的援用。

对该内存的拜访是按后进先出 (LIFO) 程序进行的。每当咱们调用新办法时,都会在堆栈顶部创立一个新块,其中蕴含特定于该办法的值,例如原始变量和对对象的援用。

当办法实现执行时,其相应的堆栈帧将被刷新,流程返回到调用办法,这样空间就又可用于下一个办法运行。

1.1 栈空间的次要个性

栈空间的其余一些个性包含:

  • 它随着新办法的调用和返回别离增长和放大。
  • 堆栈中的变量只有在创立它们的办法正在运行时才存在。
  • 当办法执行实现时,它会主动调配和开释。
  • 如果此内存已满,Java 将抛出 java.lang.StackOverFlowError.
  • 与堆内存相比,拜访此内存的速度更快。
  • 该内存是线程平安的,因为每个线程都在本人的堆栈中运行。

2. 堆空间


堆空间用于 Java 对象在运行时的动态内存调配。新对象总是在堆空间中创立,而这些对象的援用则存储在栈空间中。

这些对象具备全局拜访权限,咱们能够从应用程序中的任何地位拜访它们。

咱们能够将这个内存模型分解成更小的局部,称为世代,它们是:

  1. 新生代: 这是所有新对象被调配和老化的中央。填满时会产生 Minor GC。
  2. 老年代: 这是存储长期存活对象的中央。当对象存储在新生代时,会设置对象年龄的阈值,当达到该阈值时,对象会被挪动到老年代。

2.1 堆空间的次要个性

堆空间的其余一些个性包含:

  • 它通过简单的内存治理技术拜访,包含新生代、老年代等等。
  • 如果堆空间已满,Java 抛出 java.lang.OutOfMemoryError.
  • 拜访这块内存比栈内存慢
  • 与堆栈相比,此内存不会主动开释。它须要垃圾收集器来开释未应用的对象,以放弃内存应用的效率。
  • 与堆栈不同,堆不是线程平安的,须要通过正确同步代码来爱护。

3. 内存调配示例


基于咱们目前所学的,让咱们通过剖析一个简略的 Java 代码来展现 JVM 如何治理内存:

class Person {    int id;    String name;    public Person(int id, String name) {        this.id = id;        this.name = name;    }}public class PersonBuilder {    private static Person buildPerson(int id, String name) {        return new Person(id, name);    }    public static void main(String[] args) {        int id = 23;        String name = "John";        Person person = null;        person = buildPerson(id, name);    }}

让咱们逐渐剖析一下:

  1. 当咱们进入 main() 办法时,会在栈内存中创立一个空间来存储该办法的原语和援用。

    • 栈内存间接存储整数的原始值 id
    • Person 类型的援用变量 person 也将在栈空间中创立,它将指向堆中的理论对象。
  2. main() 调用参数化构造函数 Person(int, String) 将在前一个堆栈的顶部调配更多内存。将存储如下内容:

    • 栈空间中调用对象的 this 对象援用
    • 栈空间中的原始值 id
    • String 参数 name 的援用变量将指向堆内存中字符串池中的理论字符串
  3. main 办法进一步调用了 buildPerson() 静态方法,其进一步调配将在前一个之上的栈空间中进行。这将再次以上述形式存储变量。
  4. 堆内存会存储新创建的 Person 类型的 person 的所有实例变量

理论在内存中的调配如下图:

4. 小结


让咱们疾速总结一下栈空间和堆空间的次要区别:

参数栈空间堆空间
应用场景在线程执行期间应用整个应用程序在运行时应用堆空间
大小限度栈空间有大小限度,具体取决于操作系统,通常小于堆空间通常没有大小限度
存储内容仅存储原始变量和在堆空间中创立的对象的援用所有新创建的对象都存储在这里
存取程序它应用后进先出 (LIFO) 内存调配零碎进行拜访该内存是通过简单的内存治理技术拜访的,次要包含新生代和老年代。
生命周期栈空间只在以后办法运行时才存在只有利用程序运行,堆空间就存在
效率与堆相比,调配速度要快得多与堆栈相比调配更慢
调配和回收当一个办法被调用和返回时,这个内存将被主动调配和回收堆空间是在新对象创立时调配的,当它们不再被援用时将被回收

栈空间和堆空间是 Java 分配内存的两种根本形式,相熟它们的工作原理,将有利于咱们开发出高效运行的 Java 应用程序。


本文亦通过 NoOne's Blog 发表,更多分享请关注公众号 NoOneNoOne