2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > java内存参数设置 16G JVM: 能不能在16G机器上设置17G的堆?

java内存参数设置 16G JVM: 能不能在16G机器上设置17G的堆?

时间:2023-01-25 19:33:08

相关推荐

java内存参数设置 16G JVM: 能不能在16G机器上设置17G的堆?

这是一个很有意思的问题:假设我们现在有一台物理内存16G的机器,那么我们能否给运行于其上的Java虚拟机分配大于16G大小的堆呢?

从直觉上来说,这似乎有点不太可能。但是稍微有点操作系统知识的人就会意识到,这其实是可以的。因为当我们设置堆大小为17G的时候,其实并不是直接分配了17G的物理内存。而只是分配了17G的虚拟内存。这些虚拟内存尚没有映射到真实的物理内存上。

为了验证这个结果,做一个小实验。

public class HelloWorld {

public static void main(String[] args) {

System.out.println("Hello, world");

}

}

它会在我的Mac上运行,我的Mac物理内存16G:

很显然,我的机器已经占用了很多内存了,只剩下不多的东西。然后运行HelloWorld的main方法,设置参数:

-Xms17g -Xmx17g

将堆的大小固定为17G。

成功输出了结果:

现在我们进一步考虑这个问题,17G只是比16G大了一点点,也就是说,物理内存加上swap space,是大于17G的。如果我们将这个值设置得更加大,以至于堆大小比整个物理内存加上swap space还要大,会有什么情况呢?

设置参数

-Xms128g -Xmx128g

实际上,你可以将值设置得非常非常大,然后输出结果:

-Xms12800g -Xmx12800g

在这种设置下,依旧会输出"Hello World",但是中间有很长一段时间的卡顿,并且内存占用会一直上升,直到达到某个值:

为什么会是四十多G,这个问题我无法解释……因为我也不知道。

中间卡顿是因为操作系统分配虚拟内存。

那么又会有一个问题,堆究竟能设置到多大?

答案是,这取决于你的机器、操作系统和虚拟机。举例来说,在64位机器上运行32位的虚拟机,那么最大堆只能设置到4G——至少对于大多数的虚拟机来说4G就是上限了。

理论上来说,虚拟机的堆大小只会受到虚拟内存地址空间大小的限制。

那么,什么时候操作系统才会真的分配物理内存给虚拟机呢?

答案就是,在内存第一次被使用的时候。这个使用并不是说我新建了一个对象,然后操作系统就唰的把所有物理内存分配好了,它只是按照虚拟机的需求,分配了一点点。(实际上是,只是把使用到的这部分内存按照页映射到了物理内存上)

虚拟机有一个参数可以控制整个过程,促使操作系统在虚拟机启动的时候就直接完成物理内存的绑定。使用参数:

-Xms128g -Xmx128g -XX:+AlwaysPreTouch

JVM直接就崩掉了:

Process finished with exit code 137 (interrupted by signal 9: SIGKILL)

实际上,在Linux上,只要加上整个-XX:+AlwaysPreTouch,操作系统就会在无法满足内存需求的时候直接kill掉JVM。最大值就是物理内存+swap大小-已经使用内存。

如果我真的将堆设置那么大,并且不使用-XX:+AlwaysPreTouch选项,那么JVM能够正常运行吗?

前面的HelloWorld其实很鸡贼,因为它真正运行所需的内存非常小。现在假设,我们的确需要一个128G大小的堆,但是我们的机器只有16G物理内存和16G swap space,那么在这台机器上运行虚拟机,它能正常工作吗?

答案是,它可能能够正常启动,但是肯定不能正常运行。因为虚拟机在启动的时候,并不是直接就使用了128G,只要启动时候所需要的内存不超过物理内存+swap space大小,就能启动。但是在运行的过程中,虚拟机不断的请求真的内存,那么就会超过32G,而后虚拟机就崩掉。这并不是OOM,而是在操作系统层面上的崩掉。

使用Swap space究竟好不好

答案是很糟糕,很不好。之前有一个小伙伴咨询过我一个GC停顿时间长的问题,就是因为swap space。在GC的时候,要沿着引用链查找所有的存活对象。如果这部分对象所在的内存被放到了swap space上,那么就会引起缺页中断。极端情况下,会出现不断置换页。一个页在开始的时候没被扫描到,交换到了swap space上,而后又被载入物理内存,因为立刻又扫描它了。

JVM使用了TLB的技术,所以其空间局部性还是很好的。

所以比较好的实践是,在Linux机器上将vm.swappiness参数设置到0,也就是不适用swap space。在使用大堆的情况下,这是一个非常隐蔽的坑。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。