我最近发布了一个关于improving memory usage/GC的问题,并且已经能够使用ShortByteString
将内存消耗减少到我认为合适/比例级别(并且在此过程中从“永远”完成“只是”非常非常慢的“当前测试”,但似乎仍然会考虑过多的GC时间。
对测试进行概要分析得出以下结果:
49,463,229,848 bytes allocated in the heap 68,551,129,400 bytes copied during GC 212,535,336 bytes maximum residency (500 sample(s)) 3,739,704 bytes maximum slop 602 MB total memory in use (0 MB lost due to fragmentation) Tot time (elapsed) Avg pause Max pause Gen 0 14503 colls, 0 par 1.529s 1.681s 0.0001s 0.0164s Gen 1 500 colls, 0 par 79.202s 79.839s 0.1597s 0.3113s TASKS: 3 (1 bound, 2 peak workers (2 total), using -N1) SPARKS: 0 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled) INIT time 0.000s ( 0.001s elapsed) MUT time 29.500s ( 82.361s elapsed) GC time 47.253s ( 47.983s elapsed) RP time 0.000s ( 0.000s elapsed) PROF time 33.478s ( 33.537s elapsed) EXIT time 0.000s ( 0.025s elapsed) Total time 110.324s (130.372s elapsed) Alloc rate 1,676,731,643 bytes per MUT second Productivity 26.8% of total user, 22.7% of total elapsed gc_alloc_block_sync: 0 whitehole_spin: 0 gen[0].sync: 0 gen[1].sync: 0
以下堆可视化:
目前我正在使用似乎有帮助的-H
,并且已经尝试了增加线程,代,因子和使用压缩(-N -G -F -c
)的组合,所有这些都没有导致明显的变化或性能下降。很明显,一切都是长寿的(当我增加-G
然后gen 1统计基本上转移到最老的一代,它与gen 0之间没有任何东西),但我不明白为什么GC不能只是“不要管它”。根据我的阅读,我认为GC仅在分配空间不足时运行,但增加分配/因子/堆似乎没有效果。
为了减少GC工作量,还有什么我可以尝试的吗?或者有什么方法可以让我知道我的代码存在根本问题,这使得无法减少这段时间?我相信我必须在内存中构建一个大型数据结构,目前是ST
内可变向量的哈希表。我唯一的另一个想法是内部我的数据结构被[不必要地]复制并强制GC运行,但我正在使用ST
期望避免这种行为。
答案 0 :(得分:3)
我还没看过你的代码,所以你应该把它作为一个扩展的评论而不是一个答案。如果,正如您所说,必须构建一个非常大的结构,那么您可以采取两项措施来限制性能影响:
第一步也是最容易(但不容易!)的步骤是尽可能减少指针。一个巨大的HashMap
构建成本可能比一个巨大的哈希表要贵得多,并且由一个未装箱的向量索引。 GC无需追踪未装箱的东西,这是一个巨大的优势,但它们仍然会被它复制。您可能会发现这是可以接受的,因为复制大型连续向量应该非常便宜。
下一步是将垃圾收集器中的内容放入固定内存中。我相信标准(不小)ByteString
这样做,以及通过外部函数接口创建的数组。