【问题标题】:What is the default stack size, can it grow, how does it work with garbage collection?默认堆栈大小是多少,它可以增长,它如何与垃圾收集一起工作?
【发布时间】:2013-11-30 13:27:00
【问题描述】:

我了解每个线程都有自己的stack。原始类型和引用保存在堆栈上,并且没有对象保存在堆栈上。

我的问题是:

  • 堆栈可以增长多少? (比如参数 -Xms 和 -Xmx
  • 我们可以限制它的增长吗?
  • 堆栈是否有默认的最小值和最大值?
  • 垃圾回收如何在堆栈上工作?

【问题讨论】:

  • 只是对阅读本文的人的一点评论:Escape-Analysis(Java 6 Update 21 及更高版本)允许将对象存储在堆栈中。减少垃圾收集器的工作量。
  • GC 在堆栈上不起作用。您不能在堆栈上创建东西,因此没有什么可收集的 - JVM 本身将东西放入堆栈并在必要时将其删除。收集的“垃圾”是您创建的对象的实例。

标签: java memory stack


【解决方案1】:

正如您所说,局部变量和引用存储在堆栈中。当一个方法返回时,堆栈指针只是简单地移回到方法开始之前的位置,也就是说,所有本地数据都“从堆栈中移除”。因此,堆栈不需要垃圾收集,只发生在堆中。

回答您的具体问题:

  • 请参阅this question,了解如何增加堆栈大小。
  • 您可以通过以下方式限制堆栈增长:
    • 将多个局部变量分组到一个对象中:该对象将存储在堆中,只有引用存储在堆栈中
    • 限制嵌套函数调用的数量(通常不使用递归)
  • 对于 Windows,32 位的默认堆栈大小为 320k,64 位的默认堆栈大小为 1024k,请参阅this link

【讨论】:

  • 尽管将局部变量分组的对象存储在堆中,但当方法返回时,该对象已消失。 JVM 会做一些对象延迟。如果我错了,请纠正我
  • @asgs 这就是垃圾收集开始的地方。如果局部变量确实是对该对象的唯一引用,则该对象将在方法返回后的某个时刻被 GC 删除。如果方法对对象添加了一些外部引用,GC 不会删除它。
【解决方案2】:

堆栈可以增长多少?

您可以使用名为 ss 的 VM 选项来调整最大堆栈大小。 VM 选项通常使用 -X{option} 传递。所以你可以使用java -Xss1M来设置最大栈大小为1M。

每个线程至少有一个堆栈。一些 Java 虚拟机 (JVM) 将 Java 堆栈(Java 方法调用)和本机堆栈(VM 中的本机方法调用)放在一个堆栈中,并使用称为 M2nFrame 的“托管到本机框架”执行堆栈展开。一些 JVM 分别保留两个堆栈。在大多数情况下,Xss 设置 Java 堆栈的大小。

对于许多 JVM,他们在不同的平台上为堆栈大小设置了不同的默认值。


我们可以限制这种增长吗?

当发生方法调用时,将在该线程的堆栈上创建一个新的堆栈帧。堆栈将包含局部变量、参数、返回地址等。在 Java 中,您永远不能将对象放在堆栈上,只有对象引用可以存储在堆栈上。由于数组也是 Java 中的对象,因此数组也不存储在堆栈中。因此,如果您通过将局部原始变量和参数分组到对象中来减少它们的数量,则可以减少堆栈空间。实际上,我们不能显式地将对象放入 Java 堆栈这一事实会在一段时间内影响性能(缓存未命中)。


堆栈是否有一些默认最小值或默认最大值?

正如我之前所说,不同的虚拟机是不同的,并且可能会改变版本。见here


垃圾回收如何在栈上工作?

Java 中的垃圾收集是一个热门话题。垃圾收集旨在收集 heap 中无法访问的对象。所以这需要一个“可达”的定义。堆栈上的所有内容都构成了 GC 中根集引用的一部分。从每个线程的每个堆栈中可以访问的所有内容都应该被视为活动的。还有一些其他的根集引用,例如 Thread 对象和一些类对象。

这只是 GC 上堆栈的一个非常模糊的用法。目前大多数 JVM 都在使用分代 GC。 This article 简要介绍了 Java GC。最近我读到 a very good article 谈论 .NET 平台上的 GC。 Oracle JVM 上的 GC 非常相似,所以我认为这也可能对您有所帮助。

【讨论】:

  • 好答案。我想补充一点,我发现默认设置是保守的,它们旨在涵盖所有类型的部署。但根据我的经验,即使在应用程序服务器中运行大型应用程序(超过 500k 行代码),即使堆栈设置为 256k (-Xss256k),我也从未遇到过 StackOverflow 错误。考虑一个具有 70 个运行线程的应用服务器,默认堆栈为 1MB,即为进程增加了 70MB。
  • java -Xss 100M -jar testing.jar 抛出错误“无效的线程堆栈大小:-Xss 错误:无法创建 Java 虚拟机。”但java -Xss100M -jar testing.jar 工作得很好。使用 Java“1.8.0_112”运行 Windows 10 64 位。是否应该编辑您的帖子以删除空间?
  • 对于使用 maven 的人来说,这看起来像这样:gist.github.com/belkacemlahouel/…
  • "在 java 中,你永远不能将对象放在堆栈上...影响性能" 这不是真的!如果逃逸分析证明它们在其他任何地方都无法访问,HotSpot 会在堆栈上分配对象。这提高了缓存局部性,但更节省了 GC 成本。这是 Java 性能出色的一个主要原因。
  • 有没有办法查看你的线程使用了多少堆栈空间?知道如何更改此值很好,但我想知道是否有 JMX 指标或我可以查看的东西来告诉我我的平均和/或最大线程堆栈利用率是多少,以便我可以决定何时需要更改这个值与否。
猜你喜欢
  • 1970-01-01
  • 2011-09-30
  • 2013-12-30
  • 2012-06-07
  • 2014-01-11
  • 2021-01-20
  • 2016-10-31
  • 2011-03-06
  • 1970-01-01
相关资源
最近更新 更多