【问题标题】:Heap,Non heap and stack ..intricacies of garbage collection堆,非堆和堆栈..垃圾收集的复杂性
【发布时间】:2014-03-27 04:31:42
【问题描述】:

我一直在经历java中的垃圾收集(jdk 6热点JVM)。我有几个问题希望社区能帮助我解决。

我的理解:

1)堆分为

a)年轻一代 -Eden 和 Survivor :新的对象和数组是 创建到年轻代。次要垃圾收集将 在年轻一代中运作。还活着的物体会 从伊甸园空间移动到幸存者空间。

b)Old generation/Tenured Generation:Major collection会将仍然活着的对象从年轻代移动到老年代。

2)Non Heap分为

    a)Code Cache
    b)Perm generation.

我想知道的:

1)what if survivor gets full..how will minor garbage collection work.

2)When and how is the perm generation garbage collected.
3)Also what happens to the stack..where is it stored or residing?How is its size controlled?

【问题讨论】:

  • 如果幸存者满了,那么对象将被移动到老年代。
  • 您有多个问题。

标签: java performance garbage-collection jvm-hotspot


【解决方案1】:

堆栈是内存的一部分。在此堆栈上创建本地自动变量并传递方法参数。当一个进程启动时,它会获得一个默认堆栈大小,该大小对于每个进程都是固定的。在当今的操作系统中,一般默认堆栈大小为 1 Mb,这对于大部分进程来说已经足够了。在异常情况下,堆栈限制超出。这称为堆栈溢出。

【讨论】:

    【解决方案2】:

    堆栈大小通过在创建时固定来控制。如果您尝试使用的空间超过堆栈上的可用空间,您将收到“堆栈溢出”异常。

    【讨论】:

      【解决方案3】:
      1. 当幸存者空间已满时,对象被移入老年代。虽然,从技术上讲,大多数情况下,当一个对象从幸存者空间移动到老年代时,并不是因为幸存者空间已满,而是因为该对象已经在一定数量的次要收集中幸存下来,通常是 10-15。
      2. 非常罕见。它主要是 Java 类的二进制代码,因此只有从内存中卸载一堆类才能释放空间。大多数程序在程序的整个生命周期中都使用相同的一组类,因此收集永久代通常是浪费时间。基本上,Java 只会在即将耗尽内存时在这里进行收集。
      3. 堆栈是堆外的东西,它的大小受以下事实控制:对象只有在保证有有限的生命周期时才存储在堆栈上。这些主要是局部变量。假设您有一个本地 StringBuilder 变量,用于构建方法的返回值。您永远不会将它传递到您自己的方法之外,而是在方法结束时调用stringBuilder().toString() 来创建一个新对象。由于 Java 可以判断 StringBuilder 对象不会超过方法的运行时间,因此它可以将其放入堆栈并在方法返回时立即释放它,而不是将其传递给垃圾收集器。

      【讨论】:

      • 感谢您回复...对于 pt 2 卸载的类只有在应用程序未部署时才会发生?对吗?我正在检查我的一个应用程序,其中 jconsole 捕获的 perm 生成图是之字形的图形...你如何解释...可能是因为字符串实习生也驻留在 perm gen 中
      • @Rips 是的,卸载应用程序后可以在永久代中释放空间,但细节在很大程度上取决于您为老年代使用的垃圾收集器。带有 Java 8 的 permanent generation is gone now anyway
      • 如果我们谈论 HotSpot JVM,不可能在堆栈上分配 StringBuilder 对象。 JVM 可以内联所有 StringBuilder 方法,并将其字段转换为方法范围内的局部变量。这样一来,StringBuilder 对象就不会在堆中分配。不过,用于组成字符串的临时 char[] 将以任何方式分配在堆上。