什么是默认的堆栈大小,它可以增长,它如何与垃圾收集一起使用?

Bat*_*tty 67 java memory stack

我知道每个线程都有自己的stack.原始类型和引用保留在堆栈中,并且堆栈中没有任何对象.我的问题是:

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

Sta*_*kER 80

堆栈可以增长多少?

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

每个线程至少有一个堆栈.一些Java虚拟机(JVM)将Java堆栈(Java方法调用)和本机堆栈(VM中的本机方法调用)放入一个堆栈中,并使用Managed to Native Frame(称为M2NFrame)执行堆栈展开.一些JVM分别保留两个堆栈.Xss在大多数情况下,设置Java Stack的大小.

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

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

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

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

正如我之前所说,不同的VM是不同的,并且可能会更改版本.看到这里.

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

Java中的垃圾收集是一个热门话题.垃圾收集旨在收集堆中无法访问的对象.所以这需要'可达'的定义.堆栈中的所有内容构成GC中根集引用的一部分.每个线程的每个堆栈都可以访问的所有东西都应该被认为是实时的.还有一些其他根集引用,如Thread对象和一些类对象.

这只是在GC上使用堆栈非常模糊.目前大多数JVM都使用世代GC.本文简要介绍了Java GC.最近我读了一篇非常好的文章,谈论.net上的GC.oracle jvm上的GC非常相似,所以我认为这也可以帮到你.

  • 好答案.我只想补充一点,我发现默认值是保守的,它们旨在涵盖所有类型的部署.但根据我的经验,即使在应用程序服务器中运行大型应用程序(超过500k行代码),即使堆栈设置为256k(-Xss256k),我也从未遇到过StackOverflow错误.考虑一个具有70个正在运行的线程的应用服务器,默认的1MB堆栈,这个过程额外增加70MB. (5认同)
  • `java -Xss 100M -jar testing.jar`抛出错误"无效的线程堆栈大小:-Xss错误:无法创建Java虚拟机".但是`java -Xss100M -jar testing.jar`工作正常.使用Java"1.8.0_112"运行Windows 10 64位.您的帖子应该被编辑以删除空间吗? (4认同)
  • 有没有办法查看线程使用了多少堆栈空间?知道如何更改此值很好,但我想知道是否有 JMX 指标或我可以查看的东西来告诉我平均和/或最大线程堆栈利用率是多少,以便我可以决定何时需要更改这个值与否。 (2认同)

Vin*_*ele 12

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

回答您的具体问题:

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

  • @asgs,这就是垃圾收集开始的地方。如果局部变量确实是对该对象的唯一引用,则该对象将在方法返回后的某个时刻被 GC 删除。如果该方法向该对象添加了一些外部引用,GC 将不会删除它。 (2认同)