JVM 性能优化:调优之内存与 GC

Java虚拟机,即JVM,是Java程序中不可或缺的运行环境之一。JVM内存分为堆内存和非堆内存。堆内存用于存放Java对象实例等数据,而非堆内存则用于存放存储程序运行状态相关数据的区域。JVM的内存调优对于Java应用程序的性能优化至关重要。在这篇文章中,我们将针对内存与GC进行调优。

非堆内存调优

监控非堆内存情况

由于非堆内存与堆内存分开管理,因此会有一些与之相关的配置参数,如:PermSize, MaxPermSize,kernel.shmmax等,需要在启动JVM时进行配置。如下示例代码中的-Xms512m表示堆内存最小值为512MB,-Xmx512m表示堆内存最大值为512MB:

java -server -Xms512m -Xmx512m -XX:PermSize=64m -XX:MaxPermSize=128m -jar myApp.jar

使用JVM内置的JMX抓取系统MBean信息,可以对JVM进程中非堆配置内容进行监控,根据监控过程中捕获到的异常错误,能及时调整相关配置参数,保存消耗的优化时间。

控制方法区及时间轴

方法区又叫永久带(PermGen),它是一种JVM的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

方法区的运行时需对其进行回收。由于方法区里面的对象较为稳定,因此触发FullGC 的机会比较少,但如果永久带内存不足时,会报java.lang.OutOfMemoryError:PermGen space的错误。如果大量的Java class被反复加载/卸载,就会导致永久带空间不足。出现这种情况,可以通过调整-XX:MaxPermSize进行调优。

时间轴是一张 JVM 内存的图表,它由一系列的 “时间-使用情况” 点组成。时间轴可以明显的显示出 JVM 在某段时间内的内存使用情况。当代码带有缓存的复杂算法时,可以通过关注时间轴的值,检测是否有一些高耗内存的应用或数据结构,做到避免内存利用率下降的情况。

堆内存调优

监控堆内存情况

通过jstat命令可以查看某个进程Jvm的gc情况,包括其次数、内存使用情况等,非常方便。例如:

jstat -gcutil 8464 1000 10

其中8464表示所要检查的JVM进程ID,1000表示检查的时间间隔是1s,10表示检查十次。

jstat 命令中gcutil的输出信息包括:Young GC 的发生率YGC以及时间YGCT,FullGC的发生率FGC以及时间FGCT, 还可以输出堆内存的总大小、已使用大小、空闲大小,以及最大堆内存大小。

控制垃圾回收(GC)

堆内存过小会导致频繁的GC,这样会使程序中断耗时,一定程度上影响程序性能。

jvm的GC算法是很复杂的,我们通过下面的几个方面进行调优:

堆内存大小调整

我们可以通过调整-Xmx来调整堆内存占用大小,如果java程序运行在64位机器上时,最大可分配的堆内存约为512GB,因此,当运行的Java应用使用的内存小于512GB时,堆内存对性能调整并不是最主要的因素。

垃圾回收器设置

目前JVM中最常见的GC算法是 Parallel GC, Serial GC 和 Concurrent Mark-Sweep (CMS)。在JVM的内存回收中,根据使用情况采取不同的GC算法。

  • Parallel GC用于处理大型应用,适用于要求 CPU 的应用场合。Parallel GC 是一种并行GC,利用多线程的方式来回收堆内存。
  • Serial GC适用于小应用内存量的场景。Serial GC 比较简单,适用于单核 CPU 的情况,并且不产生过多的线程开销。
  • CMS GC适用于响应速度敏感的应用,或应用内存堆大小不足 50% 的场景。

可以通过-Xpgcmx来调整CMS GC的堆内存大小,一般推荐使用CMS GC。

线程影响

线程影响可能会导致内存利用率下降和频繁的GC,并影响堆内存调优,其中一种常见的线程影响是由过多的线程对象占用内存。

总结

在JVM性能优化中,内存和GC调优是两个重要的部分,优化好这两个方面可以显著提高应用程序性能。解决内存与GC问题,能有效避免Java应用程序的线程问题、僵尸线程等问题,正确处理好JVM中内存的开辟、回收与使用等问题,可以助力开发者们更好的进行软件开发。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/658fe2e1eb4cecbf2d5716a8


纠错
反馈