【源码编辑器故事教程】【dsmall源码】【armcc源码】jstat源码

2024-11-19 07:33:04 来源:qq病毒血腥源码 分类:焦点

1.记一次使用低版本ES Java Client偶尔查询超时问题解决过程
2.26期内存持续上升,如何排查?
3.见了鬼,我JVM的Survivor区怎么只有20M了?
4.如何了解CMS的垃圾碎片率

jstat源码

记一次使用低版本ES Java Client偶尔查询超时问题解决过程

       项目中ES使用版本2.4,ES JavaClient为2.4.4。一个地区项目中,查询ES接口偶现翻页超时现象,源码编辑器故事教程不确定翻页序号。

       进入容器,使用top 1命令查看CPU占用,发现CPU占用较低,排除了机器配置问题。使用jstat -gcutil -t 查看GC信息,发现GC正常,各内存区占用处于正常范围,GC执行次数有限,dsmall源码排除内存不足导致超时。

       问题出现在BaseFuture#get和AdapterActionFuture#actionGet位置,跟踪源码发现,BaseFuture内部Sync实现了AQS。在AQS#acquireSharedInterruptibly中调用tryAcquireShared(arg),判断是否获取共享锁。tryAcquireShared(arg)在Sync中实现,当state不为0时,返回true,state通常在ES数据获取或异常后修改。

       问题定位在查询线程和等待线程的交互中,查询线程未能及时回调结果,等待线程阻塞,导致查询失败。armcc源码

       为解决临时需求,增加重试机制,发现#actionGet方法支持设置超时时间。更换可设置超时API,并在捕获ElasticsearchTimeoutException时进行重试,问题得以解决。

       具体为何查询线程迟迟不回调,仍在进一步排查。

期内存持续上升,如何排查?

       面对内存持续上升的挑战,如何在众多进程和业务线程中找出问题根源?首先,正确选择和运用工具是关键。在Linux下,我们常借助top命令实时监控CPU和内存使用,defaultsqlsession源码top -Hp pid则能详细查看线程资源。vmstat则提供了更深入的采样分析,尤其是进程上下文切换,而pidstat则进一步到达线程层面,其参数如-p, -r和-t帮助我们深入了解内存使用。

       对于Java应用,JVM内存管理尤为重要。jstat命令能够监测Java堆内存和垃圾回收情况,帮助我们理解内存分配。jstack则用于堆栈分析,有助于死锁排查。jmap不仅可以查看堆内存配置和使用,还能输出对象信息,进行详细统计和分析。sitezj源码

       在复杂业务场景中,排查内存问题可能需要深入源码分析,甚至结合MAT工具进行堆内存dump。尽管工具是我们的助手,但实际问题的解决往往需要丰富的经验和个人的专业判断。记住,性能调优并非易事,它需要我们熟练运用这些工具,同时不断积累实战经验。

见了鬼,我JVM的Survivor区怎么只有M了?

       某日,一位同学在群里分享了使用 jmap -heap 查看内存使用情况的截图,发现 Survivor 区占比总是在%以上,这引发了讨论。通过分析图中的信息,我们注意到 Eden、From、To 之间的比例并非默认的8:1:1,这提示我们可能存在 AdaptiveSizePolicy 的影响。使用 jinfo -flags pid 确认使用的是 JDK 1.8 的默认回收算法 UseParallelGC,并且默认开启了 AdaptiveSizePolicy。这表示每次垃圾回收(GC)后,JVM 会重新计算 Eden、From 和 To 区的大小,以适应不同的 GC 时间、吞吐量和内存占用量。在默认配置下,虽然 SurvivorRatio 的默认值是8,但年轻代三个区域的比例仍会变动,从而导致 Survivor 区的大小变化。

       在讨论中,我们发现老年代的内存使用量也较高,这引起了进一步的调查。通过使用 jmap -histo 查看堆中的实例,发现有两个类的实例数量较多,分别是 ExpiringCache 和 LinkedHashMap。进一步分析发现 ExpiringCache 的构造函数初始化了一个 LinkedHashMap,这可能是问题的源头。通过分析 ExpiringCache$Entry 类和其使用场景,我们定位到问题出在使用 getCanonicalPath() 方法的类上,这会导致大量 ExpiringCache$Entry 对象进入老年代。使用 jstat -gcutil 查看 GC 情况,发现从应用启动到执行 jmap -histo 命令期间,触发了次 Full GC(FGC),耗时9.秒,平均每次 FGC 耗时约为毫秒。这表明内存管理存在优化空间。

       为了解决 Survivor 区变小、老年代占比变高的问题,有几种解决方案可以考虑。一种简单的方法是不使用缓存,可以通过设置参数-Dsun.io.useCanonCaches=false 来关闭缓存。另一种方案是保持使用 UseParallelGC,显式设置 -XX:SurvivorRatio=8,以固定年轻代三个区域之间的比例。最后,可以考虑使用 CMS 垃圾回收器,因为它默认关闭 AdaptiveSizePolicy,从而提供更稳定的内存管理。

       对于源码层面的理解,JDK 1.8 中的 UseParallelGC 和 AdaptiveSizePolicy 的互动主要通过参数配置来实现。当显式设置 SurvivorRatio 时,JVM 会确保这个参数在 Parallel Scavenge 回收器中生效,从而固定年轻代三个区域的比例。在 AdaptiveSizePolicy 的实现中,JVM 会在 GC 过程完成后根据预期停顿时间和实际的 GC 时间动态调整内存大小。然而,在使用 CMS 垃圾回收器时,JDK 1.8 中的逻辑会将 UseAdaptiveSizePolicy 设置为 false,这限制了 AdaptiveSizePolicy 的应用,从而影响内存管理的优化。

       通过这次讨论和分析,我们不仅发现了内存管理中的问题,还学习了如何通过参数配置来优化 JVM 的垃圾回收策略。对于开发者而言,了解并合理配置这些参数可以显著提升应用的性能和稳定性。

如何了解CMS的垃圾碎片率

        PrintFLSStatistics这个参考比较有用,因为CMS GC会有碎片问题,而随着碎片的越来越严重,GC性能会变差直到发生FullGC,而FullGC时STW通过会超过数秒,这对OLTP系统来说是致命的,通过这个参数可以在gc日志中输出free list方式分配内存后内存统计情况和碎片情况;

        从CompactibleFreeListSpace的描述可知CMS使用free list分配内存

        -- 源码摘自compactibleFreeListSpace.hpp:

        再看compactibleFreeListSpace.cpp中的 gc_prologue 和 gc_epilogue (prologue的中文意思是开场白,epilogue的中文意思是收场白,所以这两个方法可以理解为gc前和gc后),由两个方法的实现可知,如果JVM参数PrintFLSStatistics 不为0(负数也可以),那么每次GC前后都会调用reportFreeListStatistics()方法打印出free list的统计信息:

        再看reportFreeListStatistics的具体实现,分为两个部分来看:

        输出free list统计信息,gc日志中输出内容如下:

        Total Free Space:

        Max Chunk Size:

        Number of Blocks: 1

        Av. Block Size:

        Tree Height: 1

        如果JVM参数为PrintFLSStatistics 大于1,例如-XX:PrintFLSStatistics=2,那么还会输出IndexedFreeLists的统计信息,以及如下的gc日志,能够直观的看到碎片率,frag的值越大碎片化越严重,JVM的初始化时frag的值为0.,即没有任何碎片:

        为了查询碎片化率越来越严重的GC日志,笔者基于kafka 2.-1.1.1版本,对其GC参数进行了一些调整,从而引起不断CMS GC:

        接下来只需要启动一个kafka broker,然后利用kafka自带的压测脚本向broker发送1kw条消息(每条消息个字节):

        bin/kafka-run-class.sh org.apache.kafka.tools.ProducerPerformance --topic topic-afei-test --num-records --record-size --throughput -1 --producer-props acks=1 bootstrap.servers=.0.1.: buffer.memory= batch.size=

        由jstat可知,FGC非常严重,每2s就有好几次的FGC:

        再看gc日志,kafka默认开启了gc日志(位于:logs/kafkaServer-gc.log.0.current):

本文地址:http://04.net.cn/html/27c475495218.html 欢迎转发