当前位置: 首页 > 科技观察

Java垃圾收集调优实战

时间:2023-03-12 06:40:45 科技观察

Java垃圾收集调优不同于任何其他性能优化活动。首先,你要确保你对整个应用程序和调优的预期结果有足够的了解,而不是仅仅满足于调优应用程序的某个部分。一般来说,遵循以下过程会更容易:确定您的绩效目标。测试。测量调整结果。与目标进行比较。换个方法再测。性能调整目标是可识别和可测量的,这一点非常重要。这些目标包括延迟、吞吐量和容量,要了解有关它们的更多信息,我建议查看垃圾收集手册中的相应章节。让我们看看这些调整目标是如何在实践中设定和实现的。为此,让我们看一个示例代码:);this.objectSize=objectSize;this.queueSize=ttl*1000;}@Overridepublicvoidrun(){for(inti=0;i<100;i++){deque.add(newbyte[objectSize]);if(deque.size()>queueSize){deque.poll();}}}publicstaticvoidmain(String[]args)throwsInterruptedException{executorService.scheduleAtFixedRate(newProducer(200*1024*1024/1000,5),0,100,TimeUnit.MILLISECONDS);executorService.scheduleAtFixedRate(newProducer(50*1024*1024/1000,120),0,100,TimeUnit.MILLISECONDS);TimeUnit.MINUTES.sleep(10);executorService.shutdownNow();}}两个代码提交Job(作业),每100毫秒运行一次。每个作业模拟特定对象的生命周期:首先创建对象,让它们“活”一段时间,然后忘记它们,让GC回收内存。运行此示例时,启用GC日志记录并使用以下参数:-XX:+PrintGCDetails-XX:+PrintGCDateStamps-XX:+PrintGCTimeStamps我们立即在日志文件中看到类似于以下内容的GC影响:2015-06-04T13:34:16.119-0200:1.723:[GC(AllocationFailure)[PSYoungGen:114016K->73191K(234496K)]421540K->421269K(745984K),0.0858176secs][Times:user=0.04sys=0.069,real=0.069秒2015-06-04T13:34:16.738-0200:2.342:[GC(AllocationFailure)[PSYoungGen:234462K->93677K(254976K)]582540K->593275K(766464K),0.2357086secs][Times1:usersys0=0.,real=0.24secs]2015-06-04T13:34:16.974-0200:2.578:[FullGC(人体工程学)[PSYoungGen:93677K->70109K(254976K)][ParOldGen:499597K->511230K(761856K)]59K3K35]598121016832K),[Metaspace:2936K->2936K(1056768K)??],0.0713174secs][Times:user=0.21sys=0.02,real=0.07secs]根据日志中的信息,我们可以开始提升性能了。记住三个不同的目标:确保最坏情况下的GC暂停不会超过预期的阈值。确保应用程序线程停止的时间不超过预先确定的阈值。降低基础架构成本,同时确保我们仍然可以实现合理的延迟和吞吐量目标。为此,三种不同配置各运行10分钟,三个差异较大的结果总结如下表:HeapGCalgorithmworkseffectivelywithlongpause-Xmx12g-XX:+UseConcMarkSweepGC89.8%560ms-Xmx12g-XX:+UseParallelGC91.5%1,104ms-Xmx8g-XX:+UseConcMarkSweepGC66.3%1,610ms在实验中,我们设置不同的GC算法和不同的堆大小,运行相同的代码,然后测量垃圾收集暂停的持续时间和吞吐量。实验细节和结果解释在我们的垃圾收集手册中。查看手册中的一些示例,修改一些简单的配置可能会导致在延迟、吞吐量等方面完全不同的性能。注意:为了使示例尽可能简单,仅更改了有限数量的输入参数,例如没有针对不同数量的内核(CPU内核)或不同的堆布局进行测试。