【问题标题】:Explain the difference between contiguous allocation (memory held in a heap in the stack) vs. memory in a heap [closed]解释连续分配(堆栈中的堆中保存的内存)与堆中的内存之间的区别[关闭]
【发布时间】:2014-02-02 03:11:12
【问题描述】:

解释连续分配(堆栈中的堆中保存的内存)与堆中的内存之间的区别。

我是新手,不完全确定。

【问题讨论】:

  • 发帖前有没有做过调查?
  • 您在这里实际问的是什么?我看到两个或三个问题...没有一个与您的问题的标题直接相关。
  • 是的,我已经尝试过,但无法找到明确的直接答案,这正是我要寻找的。​​span>

标签: java allocation


【解决方案1】:

问题不是连续与堆,而是自动与堆。

自动存储在进入代码块时设置 - 传统上在进入函数或方法时 - 并在该函数返回时被丢弃,因此它在堆栈上的内存空间可以被下一个函数调用重用。这就是大多数局部变量的处理方式。显然,这对于任何打算在该函数调用结束后持续存在的东西都没有用。

在 Java 中,永远不会从自动存储中分配对象。相反,它们是在执行new 操作时根据需要从堆中分配的。坦率地说,这有几个原因,除非你正在设计一种你并不真正需要了解的编程语言,而且这个话题太大了,无法在这里讨论。重要的是,由于它们是从堆中获得的,它们的生命周期与堆栈帧无关。由于 Java 是一种垃圾收集语言,它们的内存将在最后一次引用它们消失后的某个时间自动恢复以供重用——同样,细节太大了,无法在这里讨论,但基本上你可以相信 GC 来了时不时地捡起掉在地板上的衣服,然后扔进洗衣房。

【讨论】:

  • 另请参阅本页右侧“相关”下的几个答案。和/或澄清你对什么感到困惑。
【解决方案2】:

堆栈帧仅在方法调用的生命周期内存在,这意味着分配内存以存储所有局部变量和方法参数,这些变量和方法参数以某种方式帮助帮助方法实现其任务目标它着手实现。

堆栈帧中的内存存储示例是临时指针,用于跟踪您正在迭代的数组中的索引位置。循环结束后,栈帧会从栈中弹出,这意味着分配给局部变量和方法参数的所有临时内存都被释放回系统中。

堆是不同的,因为它是对象所在的地方,而不是指向对象的“指针”。

当我学习时,我发现很难弄清楚两者之间的区别。 帮助我的关键点是,指向对象的指针保存在堆栈帧中,它分配了一点临时内存,在方法调用的整个生命周期中都存在。因此,您只能在方法处于“范围”内时访问对象。

指针包含一个内存地址,该地址指向存储在堆上的对象的位置。这允许您引用对象以在以后更改对象状态。

  public static void main(String[] args)
  {
    Person person = new Person("Steven", 30);
  }

当你运行这个程序时:

  1. new 关键字意味着 java 将在堆上为存储 Person 对象实例变量所需的空间分配内存。

要理解的重要部分是,存储对象方法不需要内存。调用方法时,会创建一个新的堆栈帧,该堆栈帧会在方法调用期间分配临时内存。使用上面的例子,一个 Person 有 2 个实例变量,一个 String name 和一个 int age。这意味着此 Person 对象所需的内存是存储 String 类型的 reference 变量(堆上 String 对象的内存地址的位模式)和保存该位所需的内存int 的模式。

最后,main 方法也是一个堆栈帧,因此当 main 完成时,您不再拥有对 Person 对象的引用或访问可能存在于 main 中的任何临时变量。

对于任何方法都是如此,如果您有一个创建对象但不返回对该对象的引用的方法,那么您将永远无法访问该对象,Java 垃圾收集器稍后会出现并清理堆上所有没有指向它们的引用的对象。

如果你刚开始,我强烈建议你先用 java。这是一本很棒的 IMO 书籍,以易于理解的方式涵盖了这些主题。

【讨论】:

    【解决方案3】:

    当我们谈论内存或磁盘分配时,“连续”这个词只是意味着“没有任何间隙”。

    • 单个堆栈或堆内存分配始终是连续的......在我遇到的每个编程语言运行时中,讨论分配是有意义的。

    • 如果各个分配之间没有间隙,则分配序列是连续的。

    这与堆栈与堆正交。堆栈分配和堆分配都可以是连续的……也可以是不连续的。


    嗯……不完全正交。

    如果您谈论的是严格连续的内存地址(物理或虚拟),典型堆节点由应用程序可以使用的内存区域以及一个小的节点标头组成。因此,如果您查看两个连续堆节点的可用内存,则存在一个间隙……包括节点标头……这会阻止应用程序将两个区域用作单个连续区域。 (而且你最好不要尝试'cos,如果你覆盖了节点头,可能会发生不好的事情。)

    但是,当我们谈论 Java 时,这无关紧要。 Java 不允许应用程序将对象或数组连接在一起。 (这将是对运行时类型安全的根本违反。)所以地址范围中的概念上的差距并不重要。在 Java 上下文中,我们会说两个对象是连续的,忽略堆节点/对象头。


    此外,在 Java 中,您也不能显式地在堆上分配东西。在经典的 JVM 中,只有包含原始类型和引用的局部变量才会进入堆栈。没有办法说“在堆栈上分配这个数组”。 (JVM 在某些情况下可能会做后者,但它对应用程序是完全透明的,当然不是您可以使用的东西。)

    【讨论】:

      猜你喜欢
      • 2011-03-29
      • 2011-05-28
      • 2011-10-09
      • 2023-03-03
      • 2012-12-05
      • 2021-04-08
      • 2011-06-13
      • 2017-01-20
      相关资源
      最近更新 更多