我们正在使用Java运行一个RT系统。它经常使用相对较大的堆(100+GB),并处理来自消息队列的请求。每个请求必须快速处理(<100ms)以满足SLA。
我们遇到了严重的GC相关问题,因为通常情况下GC会在请求期间引起停顿(200+ms),导致失败。
我们的一位开发人员具有合理的GC知识,花费了相当长的时间来调整GC参数并尝试不同的GC。几天后,他提出了一些参数设置,我们戏称其为“基于遗传算法演化而来”。它降低了GC暂停时间,但仍远未达到满足SLA要求的水平。
我寻找的解决方案是从GC中保护某些关键代码部分,在请求完成后,让GC尽可能多地工作,然后再处理下一个请求。偶尔在请求之外暂停是可以接受的,因为我们有几个工作者,进行垃圾回收的工作者只需暂停一段时间即可。
我有一些想法,它们看起来很愚蠢、丑陋,并且很可能不起作用,但希望它们能说明问题:
我们遇到了严重的GC相关问题,因为通常情况下GC会在请求期间引起停顿(200+ms),导致失败。
我们的一位开发人员具有合理的GC知识,花费了相当长的时间来调整GC参数并尝试不同的GC。几天后,他提出了一些参数设置,我们戏称其为“基于遗传算法演化而来”。它降低了GC暂停时间,但仍远未达到满足SLA要求的水平。
我寻找的解决方案是从GC中保护某些关键代码部分,在请求完成后,让GC尽可能多地工作,然后再处理下一个请求。偶尔在请求之外暂停是可以接受的,因为我们有几个工作者,进行垃圾回收的工作者只需暂停一段时间即可。
我有一些想法,它们看起来很愚蠢、丑陋,并且很可能不起作用,但希望它们能说明问题:
- 在接收线程中偶尔调用
Thread.sleep()
,希望GC在此期间能够起到一些作用, - 在请求之间调用
System.gc()
或Runtime.gc()
,再次无望地祈求它能有所帮助, - 使用类似https://dev59.com/FXM_5IYBdhLWcg3wNgKY#6915221这样的hacky模式来混淆代码。
最后一个重要的注意事项是,我们是一个低预算的初创公司,商业解决方案如Zing®对我们来说不是一个选项,我们正在寻找非商业解决方案。
有什么想法吗?我们会完全重写我们的代码到C++(我们一开始并不知道GC可能是问题而不是解决方案),但是代码库已经太大了。
HashMap<String,Double>
对象,意味着有很多Double
包装器而不是基元类型,所有这些最终都被丢弃。我们会认为提供足够的RAM以防止OutOfMemoryError
是我们的责任,但我理解您的观点。考虑到您所说的,您认为创建一个共享的HashMap<String,Double>
池进行回收是否有帮助,或者我们的大部分问题来自包装器? - TregoregHashMap
图中几乎所有对象都与条目相关联;无论您是否重用地图,它们都将变为垃圾。如果这些是问题的重要因素,则可能想出一种用double[]
替换它们的方法会有所帮助,前提是这样做不需要在其他地方创建与节省的地图数量一样多的额外对象。 - John Bollinger