欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java应用性能调优之详解System的gc垃圾回收方法

程序员文章站 2023-11-08 20:02:10
一、什么是System.gc()? 是用Java,C#和许多其他流行的高级编程语言提供的API。当它被调用时,它将尽最大努力从内存中清除垃圾(即未被引用的对象)。名词解释:GC,Garbage Collection,垃圾回收,下文会经常使用。 二、谁可以调用System.gc()? 可以从应用程序堆 ......

一、什么是system.gc()?

system.gc()是用java,c#和许多其他流行的高级编程语言提供的api。当它被调用时,它将尽最大努力从内存中清除垃圾(即未被引用的对象)。名词解释:gc,garbage collection,垃圾回收,下文会经常使用。

二、谁可以调用system.gc()?

 system.gc() 可以从应用程序堆栈的各个部分调用:

  • 您自己开发的应用程序可以显式的调用 system.gc() 方法。
  •  system.gc() 也可以由您的第三方库,框架触发。
  • 可以由外部工具(如visualvm)通过使用jmx触发
  • 如果您的应用程序使用了rmi,rmi会定期调用 system.gc() 。

三、调用system.gc()有什么弊端?

当 system.gc() 或 runtime.getruntime().gc()api被调用时,将触发完整的gc事件。在gc完成之前,整个jvm将冻结(即正在运行的所有服务将被暂停),通常完整的gc需要很长时间才能完成。因此在不合适的时间运行gc,将导致不良的用户体验,甚至是崩溃。
jvm具有复杂的算法,该算法始终在后台运行,进行所有计算以及有关何时触发gc的计算。当您显式调用system.gc()调用时,所有这些计算都将被抛掉。

四、哪些场景适合显式调用system.gc()?

gc操作应该由jvm自行控制,在绝大部分的场景都不建议程序员手动写代码显式进行system.gc()操作,但是也不排除其中个别例外:在我们开发多个微服务时,每个服务都有多个备份节点。在非业务高峰时段,我们可以从微服务-负载均衡的节点池中取出其中一个jvm实例。然后通过该jvm上的jmx显式触发system.gc()调用,一旦gc事件完成并且从内存中清除了垃圾,将该jvm放回到微服务-负载均衡的节点池中。
当然这个过程需要很好的微服务管理及服务发布机制配合,这样既能保证jvm垃圾内存的有效清理,又不影响业务的正常运行。

五、如何检测您的应用程序正在进行system.gc()?

如第二小节所讲: system.gc() 可以从多个渠道进行的调用,而不仅仅是从您的应用程序源代码进行的调用。因此,搜索您的应用程序代码system.gc() 字符串,不足以知道 gc是否正在被调用。这就构成了一个挑战:如何检测应用程序是否正在进行垃圾回收?这就是gc日志派上用场的地方。

// java 8 启用gc日志:
// -xx:+printgcdetails -xloggc:<gc-log-file-path> ,例如下面这行代码
-xx:+printgcdetails -xloggc:/opt/tmp/myapp-gc.log

// java 9 启用gc日志:-xlog:gc*:file=<gc-log-file-path> ,例如下面这行代码
-xlog:gc*:file=/opt/tmp/myapp-gc.log

建议始终在所有生产服务器中始终启用gc日志,因为它有助于您排除故障并优化应用程序性能。启用gc日志只会增加微不足道的开销。还可以将您的gc日志上传到垃圾收集日志分析器工具,例如gceasy,hp jmeter等。这些工具将生成丰富的垃圾收集分析报告。

java应用性能调优之详解System的gc垃圾回收方法

上图摘自gceasy生成的报告。

六、如何禁止gc显式调用或调整调用gc的频率?

如果我们就是想避免程序员显式调用gc,避免不成熟的程序员在不合适时间调用gc,避免人为造成的gc崩溃,该怎么办?可以通过如下方法:

搜索和替换

在代码库中搜索 system.gc() 和runtime.getruntime().gc()。如果看到匹配项,则将其删除。但是这种方法无法避免第三方库、框架或通过外部源进行调用,那么参考第二种方法。

通过jvm参数强制禁止

通过传递jvm参数  -xx:+disableexplicitgc来强制禁止显式调用。这种方式强制、有效,应用程序内的任何gc显式代码调用system.gc() 都将被禁止生效。jvm自身的gc策略不受此参数影响,只禁止人为的触发gc。

rmi

如果您的应用程序正在使用rmi,则可以控制gc调用的频率 。启动应用程序时,可以使用以下jvm参数配置该频率:

  •  -dsun.rmi.dgc.server.gcinterval=n
  •  -dsun.rmi.dgc.client.gcinterval=n

这些属性的默认值在

  • jdk 1.4.2和5.0是60000毫秒(即60秒)
  • jdk 6和更高版本是3600000毫秒(即60分钟)

如果您的应用主机内存资源非常富余,您可以将这些属性设置为很高的值,以便可以将gc带来的对应用程序的影响最小化。这也是应用程序性能优化的一种方式之一。

期待您的关注