Hello! 欢迎来到小浪资源网!



理解 Java 内存模型:堆和栈解释


理解 Java 内存模型:堆和栈解释

了解 Java 如何处理按值传递和按引用传递后,下一步是更深入地研究 java 的内存模型。具体来说,我们将探讨——java 内存管理的两个关键组件。清楚地理解这些概念将帮助您编写高效的代码。

java中的是什么?

在java中,程序使用的内存分为两个主要区域:

1.堆内存:用于对象和类实例的动态分配。

2.stack memory:用于存储方法调用细节、局部变量和引用。

立即学习Java免费学习笔记(深入)”;

堆内存:动态内存池

  • 用途:堆是存储所有对象及其实例变量(字段)的地方。
  • 特点: 由所有线程共享。对象保留在堆中,直到不再被引用为止,此时它们就有资格进行垃圾回收。在运行时分配。
  • 用法示例: 使用 new 关键字创建的任何对象都驻留在堆中。

堆栈内存:执行上下文

  • 用途:堆栈用于管理方法执行和局部变量(原语和对象引用)。​​
  • 特点: 每个线程都有自己的堆栈(线程本地内存)。遵循后进先出 (lifo) 原则。当方法被调用和返回时自动分配和释放。
  • 用法示例: 方法调用、局部变量和对象引用都存储在堆栈中。

堆与堆栈:主要区别

feature stack heap
storage method calls, local variables objects and instance variables
access lifo (fast) dynamic access (slower)
Thread ownership thread-local shared across all threads
lifetime limited to method execution exists until garbage collected
size smaller and fixed larger and grows dynamically
management automatically managed managed by garbage collector

堆和栈如何协同工作

要了解堆和堆栈如何交互,让我们回顾一下按值传递和按引用传递

  1. 原始类型: 直接存储在栈中。 作为副本按值传递。
  2. 对象参考: 引用(内存地址)存储在堆栈中。 实际的对象存储在堆中。 当传递给方法时,引用被复制,但它仍然指向同一个堆对象。

代码示例:实际的堆和栈

让我们分析一个简单的程序来了解堆和堆栈内存是如何使用的。

class person {     string name;      person(string name) {         this.name = name;     } }  public class heapstackexample {     public static void main(string[] args) {         int number = 10; // stored in the stack         person person = new person("alice"); // reference in stack, object in heap          system.out.println("before: " + person.name); // output: alice         modifyperson(person);         system.out.println("after: " + person.name); // output: bob     }      public static void modifyperson(person p) {         p.name = "bob"; // modifies the object in the heap     } }  

内存崩溃:

  • 堆栈内存:
    • number:直接存储在栈中。
    • person:存储在栈中的引用,指向堆中的person对象。
    • p:人员引用的副本,也存储在堆栈中。
  • 堆内存:
    • 一个具有名称字段的 person 对象(最初为“alice”,修改后为“bob”)。

方法调用如何影响堆栈

调用方法时:

  • 创建一个新的堆栈帧来存储:
    • 方法参数。
    • 局部变量。
    • 实例方法对当前对象(this)的引用。
  • 当该方法返回时,其堆栈帧将被删除,从而释放内存。

这是一个例子:

public class stackdemo {     public static void main(string[] args) {         int result = calculate(5); // call method, push stack frame         system.out.println(result); // output: 25     }      public static int calculate(int n) {         return n * n; // stack frame includes 'n'     } }  

内存使用情况:

  • main方法为自己创建一个栈帧。
  • 当调用calculate(5)时,会推送一个新的堆栈帧。
  • 计算完成后,其框架将弹出,并释放内存。

堆和堆栈的常见问题

  • stackoverflowerror:
    当堆栈内存不足时发生,通常是由于深度递归或无限方法调用。

  • 示例:

public class stackoverflowexample {     public static void recursivemethod() {         recursivemethod(); // infinite recursion     }      public static void main(string[] args) {         recursivemethod();     } }  
  • 内存不足错误:堆空间:
    当堆已满且无法为新对象分配更多内存时发生。

  • 示例:

import java.util.ArrayList;  public class HeapOverflowExample {     public static void main(String[] args) {         ArrayList<int[]> list = new ArrayList<>();         while (true) {             list.add(new int[100000]); // Keep allocating memory         }     } }  

优化堆和堆栈的使用

堆:

  • 仅在必要时使用对象。
  • 对昂贵或重复的对象使用对象池。
  • 避免创建不必要的引用,从而阻止垃圾回收。

堆:

  • 避免深度递归
  • 使用有效的算法来减少方法调用的次数。

要点

  • 堆和栈一起工作:
    • 对象存储在堆中,而引用和局部变量存储在堆栈中。
  • 堆栈更快但有限:
    • 它会随着方法调用而自动增大和缩小。
    • 专为临时、线程本地数据而设计。
  • 堆更大但共享:
    • 用于需要在单个方法调用之外保留的对象。
    • 由垃圾收集器管理。
  • 了解限制:
    • 通过受控递归避免堆栈溢出
    • 优化对象创建以避免堆内存问题。

深入了解 java 中堆和栈内存的工作原理,您将能够更好地编写高效、无错误的程序,并了解 java 如何在幕后管理内存。

相关阅读