【问题标题】:Stack/Heap in JVMJVM中的堆栈/堆
【发布时间】:2016-04-29 19:52:34
【问题描述】:

我来自C/C++背景,其中一个进程内存分为:

  • 每个线程堆栈
  • 说明
  • 数据

我试图了解 JVM 是如何工作的,我查看了不同的资源,我发现 JVM 内存也分为堆和堆栈以及其他一些东西。

我想围绕这一点思考一下,当我在 JVM 中阅读堆和堆栈时,我们是在谈论堆栈和堆的概念吗?并且整个 JVM 的实际内存都驻留在堆上(这里我指的是堆的 C++ 概念)?

【问题讨论】:

  • JVM 仍然是运行在操作系统中的 C 程序。唯一的区别是 JVM 有一个托管堆,它是一个由 JVM 在 C 堆内管理的连续区域。线程栈还是栈,代码区还是一样的。等

标签: java c++ memory-management jvm


【解决方案1】:

我想围绕这一点,当我在 JVM 中阅读堆和堆栈时,我们在谈论堆栈和堆的概念吗?

是的,一般情况下是这样。每个线程都有自己的每线程堆栈,用于将局部变量存储在堆栈帧中(对应于方法调用)。堆栈不需要位于与操作系统级别的每个线程堆栈相关的位置。如果堆栈尝试增长到超过-Xss 指定的大小或实现设置的默认大小,则会抛出StackOverflowError

堆栈可以存在于 C/C++ 堆内存中,并且不必是连续的 (JVM spec v7):

每个 Java 虚拟机线程都有一个私有的 Java 虚拟机堆栈,与线程同时创建。 Java 虚拟机堆栈存储帧(第 2.6 节)。 Java 虚拟机堆栈类似于 C 等传统语言的堆栈:它保存局部变量和部分结果,并在方法调用和返回中发挥作用。因为除了推送和弹出帧外,Java 虚拟机堆栈永远不会被直接操作,因此帧可能是堆分配的。 Java 虚拟机堆栈的内存不需要是连续的。

Java 堆是一种存储对象的方法,包括在无法通过强引用访问对象时自动进行垃圾回收。它在 JVM 上运行的所有线程之间共享。

Java 虚拟机有一个在所有 Java 虚拟机线程之间共享的堆。堆是为所有类实例和数组分配内存的运行时数据区域。

堆是在虚拟机启动时创建的。对象的堆存储由自动存储管理系统(称为垃圾收集器)回收;对象永远不会被显式释放。 Java虚拟机假设没有特定类型的自动存储管理系统,存储管理技术可以根据实现者的系统要求来选择。堆可以是固定大小的,也可以根据计算的需要进行扩展,如果不需要更大的堆,则可以收缩。堆的内存不需要是连续的。

通过简单地调用构造函数(例如HashMap foo = new HashMap()),JVM 将在堆上为该对象分配必要的内存(如果不可能,则抛出 OutOfMemoryError)。同样重要的是要注意对象永远不会存在于堆栈中——只有对它们的引用才会存在。此外,非原始字段也总是包含对对象的引用。

还可以通过某些 JVM 上的sun.misc.Unsafe、分配直接缓冲区的某些 NIO 类以及通过使用 JNI 来分配堆外内存。此内存不是 JVM 堆的一部分,也不会进行自动垃圾收集(这意味着它需要通过诸如 delete 之类的方式释放,但它可能是 C++ 可能引用的堆内存的一部分。

【讨论】:

  • 感谢您的回答。您能否阐明线程(Java 堆端)和本机线程(本机堆端)如何交互?如果线程 T1 初始化 int a = 5 你是说这不会映射到本机线程堆栈吗?为什么?为什么不?如果有,怎么做?
  • @Kam int a = 5 将成为堆栈帧的一部分,它不需要位于本机线程堆栈中,因为堆栈帧通常不需要位于本机线程堆栈上。本机线程堆栈将包含解释字节码的本机代码中的局部变量。通常,Java 线程 以 1:1 的比例映射到 OS 线程,但也有可能拥有所谓的 "green threads",这在如今的非嵌入式 Java 上几乎不存在。
  • 啊,我明白了,也许我误解了每个 Java 线程都映射到本机线程的读数。谢谢!
  • @Kam Java 线程不需要映射到本机线程,但它们通常在大多数平台上以 1:1 映射,因为它们获得了某些本机并发性的好处提供给本机线程的功能。
  • 那么本地堆栈也映射了吗?
猜你喜欢
  • 1970-01-01
  • 2017-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-23
  • 2014-10-23
  • 1970-01-01
  • 2013-11-05
相关资源
最近更新 更多