半年前一时兴起,跟风开发过一个贪吃蛇小游戏。只做了单机版,随后就失去了兴趣。项目地址:https://github.com/jmecn/Snake
这个项目在运行时,内存占用量非常大。起步就有100MB,随着运行时间增加,内存消耗越来越大。5分钟后差不多就消耗了1GB内存。
我猜测问题是由于Zay-ES工作时创建了大量的对象实例导致的。GC回收不及时,导致这些对象一直保留在堆内存中。因为这个原因,我认为Zay-ES框架有内存泄露(Memory Leak),最终因此放弃了这个项目。
学习JVM的工作方式之后,我才明白这不是Zay-ES的错。是我没有设置好JVM的堆内存,所以出现了这个结果。
祭出Visual VM,查看对内存的使用情况。
- 蓝色线:已使用内存(Used Memory)
- 黄色线:堆大小(Heap Space)
从上图中可以发现,这个程序运行时所需的最低内存大概只有20MB左右。由于没有设置堆的大小,JVM认为可以使用尽量多的内存(1GB),因此GC的执行频率很低。只有在已使用内存接近堆内存上限时,才执行一次GC,并扩大堆内存的上限。
上图中,已使用的内存峰值接近250MB,我决定将JVM堆的容量设置为256MB,看看结果会有什么不同。
-Xms256m -Xmx256m
GC的频率明显变高了,而且实际使用的内存只有不到128MB!这已经说明Zay-ES其实并没有内存泄露。
再度调整堆的大小,改为启动内存32MB,最大内存128MB。
-Xms32m -Xmx128m
这一次运行,GC的回收频率更高了,已使用内存的大小也更加稳定。
不过这个设置的GC频率太高,而且中途还有一次full gc,程序卡顿非常明显,游戏感受不太舒服。
于是我把启动内存提高到64MB,最大内存依然控制在128MB。
-Xms64m -Xmx128m
这次运行流畅多了,而且内存消耗也在接受范围内。