我需要设置MaxMetaspaceSize吗?

63

因此,在询问这个问题后,很快就明确了一个重要问题并不是“我应该如何”,而是“我是否应该”?

我们有客户正在从Java7迁移到Java8(使用Tomcat7)。 Java7需要设置-XX:MaxPermSize一些客户由于个人需求和使用情况而将其最大值增加到安装程序默认设置之上

对于已定义自定义最大值的客户,我是否应该设置-XX:MaxMetaspaceSize(以前的-XX:MaxPermSize设置)?对于新的安装,应该设置-XX:MaxMetaspaceSize吗?

这样做的利弊是什么?


3
我知道,默认情况下,Metaspace 没有限制。但是现在它在本地内存中,如果没有设置限制,就有可能消耗所有系统内存。 那么,我的应用程序抛出 OOM 还是系统崩溃(没有明显的原因)更好呢? 通过添加 MaxMetaspaceSize,我是否增加了 OOM 导致系统崩溃的风险,而这本来不是一个风险? - LimaNightHawk
3
我会设定一个最大值,这个值足够大,以至于在正常情况下不会触发。我之所以这么说是因为,如果本地内存耗尽或出现疯狂的交换过程,系统可能会表现得非常不稳定且难以控制,比OOM或Java冻结更糟糕。例如,使用2GB(预计系统至少有2GB缓冲区可用)。 - eckes
@eckes,您能将此移至答案部分吗?这是值得考虑的。 - LimaNightHawk
5
不是 --XX:MaxMetaspaceSize,而是 -XX:MaxMetaspaceSize。在 XX 前只有一个 -。 - Diablo
3个回答

48

正如我在之前的回答中所评论的,限制这些内存池的原因是不同的。

如果您的用户先前将MaxPermSize提高到默认值以上,那么可能是为了避免Full GC / CMS并发模式故障,或者是因为他们的应用程序确实需要大量的perm gen空间。

将元空间限制从其有效无限的默认值降低将服务于完全不同的目的:避免无限的元空间增长。

问题在于这只是一个上限。实际提交的当前元空间大小会更小。实际上,有一个名为MaxMetaspaceFreeRatio(默认为70%)的设置,这意味着实际的元空间大小永远不会超过其占用空间的230%。

为了使其增长,它首先必须填满,强制进行垃圾收集(元空间已满),以释放对象,并且仅当它不能达到其MinMetaspaceFreeRatio(默认为40%)目标时,它会将当前元空间扩展到GC周期后占用空间的230%以下。

因此,实际的元空间大小在实践中应该稳定在接近其实际需求的范围内,除非应用程序不断泄漏类加载器/类或生成大量动态代码。

简而言之:可能有限制元空间大小的原因,但它们很可能与设置perm gen大小的最初原因不同。因此,需要重新评估需求。


如果我在Java/Android项目中进行构建/编译,并且有32 GB的RAM,那么我应该为MaxMetaspaceSize设置哪个值? - user924

6

仅就相反的意见而言,可以将案例制定为始终设置MaxMetaspaceSize。将全球所有应用程序分组成10个(二进制 - 想想看)组,可以讨论为什么要这样做。但请记住,设置限制只控制垃圾回收(GC)发生的时间。

第01组:所有非动态类的应用程序

这个组将您置于上述稳定带中。在这种情况下,要确定的大小相当容易(就像MaxPermSize一样),并且不会有太多GC。

第10组:具有动态类的应用程序

鉴于高度强大的第三方库的大量使用,几乎每个应用程序都属于此组?通常情况下,您并不关心库是Scala/Groovy等语言,因为它恰好符合您的需求,所以就使用了。填满Metaspace的死(动态)类的垃圾有何价值?当GC到来时,就会变得非常昂贵。我宁愿限制其大小,使GC更加频繁(但每个应用程序的暂停时间更短),并且更容易在同一硬件上运行多个应用程序,而不必担心它们的各自元空间相互运行。


3

@eckes 评论中的答案:

我会设置一个最大值,这个值应该足够大以避免在正常情况下触发。我这么说的原因是,如果本地内存耗尽或发生不受控制的交换,系统可能表现得非常不稳定且难以控制。比OOM或Java freeze更糟糕的是。例如使用2GB(期望系统至少有2GB缓冲区可用)。


1
我在我们的一个UAT环境中遇到了本地内存泄漏的问题。我们从未能够从这种情况中恢复,唯一的解决方案是强制重启。 - Diablo

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