为什么要减小Java JVM线程堆栈的大小?

12

我正在阅读一篇关于在Java(和JBoss平台)处理内存溢出错误条件的文章,并看到了这个建议:减少线程堆栈的大小。

减少线程堆栈的大小如何帮助解决最大内存错误条件?


1
因为栈上的数据较少? - Tedil
4个回答

10
当Java创建一个新的线程时,它会预先分配一个固定大小的内存块作为该线程的堆栈。通过减少这块内存的大小,您可以避免内存不足的问题,特别是在有大量线程的情况下 - 内存节约是堆栈大小减少乘以线程数。
这样做的缺点是增加了Stack Overflow错误的出现概率。
请注意,线程堆栈是在JVM堆之外创建的,因此即使堆中有足够的内存可用,由于内存不足(或者像Tom Hawtin正确指出的那样,地址空间不足),仍可能无法创建线程堆栈。

好的,我会使用VirtualVm进行跟踪,并尝试弄清楚堆栈空间是否需要更改。我猜它不需要改变。 - djangofan

4
问题存在于32位JVM上,地址空间可能会被耗尽。减少最大堆栈大小通常不会减少实际分配的内存量。考虑到8k线程,其中256kB保留为1k或2MB堆栈的大小,那么31位的地址空间(2GB)就用完了。
在64位JVM上,问题几乎消失了(尽管实际内存量会增加一些,因为引用大小加倍)。或者,使用非阻塞API可以减少对如此多线程的需求。

1
Hotspot 6u14引入的压缩对象指针有助于缓解这个问题。http://wikis.sun.com/display/HotSpotInternals/CompressedOops - Chris Dolan

2

一个进程中有N个线程,每个线程栈分配M字节的内存。栈使用的总内存为N x M。

您可以通过减少线程数(N)或减少分配给每个线程的内存(M)来减少栈消耗的总内存。


通常,线程不会使用栈的所有空间。它是预先分配的,以防万一以后可能需要,但如果线程不使用深度调用路径或不使用递归,则可能不需要分配给其栈的所有空间。

找到最佳的栈大小可能需要一些技巧。


2

在尝试更改线程堆栈大小之前,我建议您尝试其他方法(例如更改生存者比率或为类定义分配的空间大小)。由于很难正确设置线程堆栈大小,因此很容易出现堆栈溢出错误(这与内存不足错误一样致命)。


即使经过仔细检查,我也从未正确地设置过线程堆栈大小。但是,换句话说,我可能从未遇到过可以通过更改其线程堆栈大小来微调的Web应用程序/容器组合。我在修改生存者比率方面取得了更好的结果,而且这不会导致致命错误。但这是基于我的工作经验。在不同的工作场所和应用程序中,情况可能有所不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接