默认堆栈大小是多少,可以增加吗,它如何与垃圾回收一起使用?


77

我知道每个线程都有自己的线程stack。基本类型和引用保留在堆栈上,并且没有对象保留在堆栈上。

我的问题是:

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

对于阅读本文的人来说,这只是一点点:Escape-Analysis(Java 6 Update 21和更高版本)允许将对象存储在堆栈中。减少垃圾收集器的工作。
miracle_the_V 2015年


GC在堆栈上不起作用。您无法在堆栈上创建事物,因此没有什么可收集的-JVM本身将内容放入堆栈并根据需要将其删除。收集的“垃圾”是您创建的对象的实例。
mvmn

Answers:


94

堆栈可以增长多少?

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

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

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

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

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

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

如前所述,不同的虚拟机是不同的,并且可能会随着版本而变化。看这里

垃圾收集如何在堆栈上工作?

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

这只是GC上堆栈的一个非常模糊的用法。当前,大多数JVM使用的是世代GC。本文对Java GC进行了简要介绍。最近,我读了一篇非常好的文章,内容涉及.net上的GC。oracle jvm上的GC非常相似,因此我认为这也可能对您有所帮助。


5
好答案。我想补充一点,我发现默认值是保守的,它们旨在涵盖所有类型的部署。但是以我的经验,即使在应用程序服务器中运行大型应用程序(超过50万行代码),即使将堆栈设置为256k(-Xss256k),我也从未遇到过StackOverflow错误。考虑一个具有70个正在运行的线程的应用服务器,其默认堆栈为1MB,这是该进程的额外70MB。
brettw

6
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/…–
belka

1
“在Java中,永远不能将对象放在堆栈上……会影响性能。”这不是事实!如果转义分析证明对象在其他任何地方都无法访问,则HotSpot将在堆栈上分配对象。这样可以提高缓存的局部性,但是甚至可以节省GC成本。这是Java出色性能的主要原因。
Aleksandr Dubinsky

13

如您所说,局部变量和引用存储在堆栈中。当方法返回时,堆栈指针将简单地移回方法启动之前的位置,即所有本地数据都“从堆栈中删除”。因此,堆栈上不需要垃圾收集,仅在堆中发生。

要回答您的特定问题:

  • 有关如何增加堆栈大小的信息,请参见此问题
  • 您可以通过以下方式限制堆栈的增长:
    • 将一个对象中的许多局部变量分组:该对象将存储在堆中,而只有引用存储在堆栈中
    • 限制嵌套函数调用的数量(通常不使用递归)
  • 对于Windows,对于32位,默认堆栈大小为320k,对于64位,默认堆栈大小为1024k,请参阅此链接

尽管将局部变量分组的对象存储在堆中,但是当方法返回时,该对象已消失。JVM将执行某种对象延迟。如果我错了
指正

1
@asgs将启动垃圾回收。如果局部变量确实是对该对象的唯一引用,则该方法返回后的某个时刻,该对象将被GC删除。如果该方法向该对象添加了一些外部引用,GC将不会删除它。
Vincent van der Weele 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.