hankcs / HanLP

中文分词 词性标注 命名实体识别 依存句法分析 成分句法分析 语义依存分析 语义角色标注 指代消解 风格转换 语义相似度 新词发现 关键词短语提取 自动摘要 文本分类聚类 拼音简繁转换 自然语言处理
https://hanlp.hankcs.com/
Apache License 2.0
33.99k stars 10.18k forks source link

优化resize,避免fgc #1889

Open qiangwang opened 8 months ago

qiangwang commented 8 months ago

优化resize,避免fgc

Description

增加每次resize的大小来减少resize次数,避免生成大量大数组引发fullgc

Type of Change

Please check any relevant options and delete the rest.

How Has This Been Tested?

对比resize方法调用次数,优化后次数明显下降,同时考虑到build最后会执行shrink方法,build完成后不会引起额外的内存消耗

Checklist

Check all items that apply.

qiangwang commented 8 months ago

@hankcs 麻烦评审下

w6et commented 8 months ago

优化resize,避免fgc

我是看客,我是看到resize、shrink 都在build方法里,是前后调用,也不是循环体,为什么同一个方法内,先多申请一些,然后再shrink,能避免多次resize、fgc??所以有点儿好奇你的调用场景

qiangwang commented 7 months ago

优化resize,避免fgc

我是看客,我是看到resize、shrink 都在build方法里,是前后调用,也不是循环体,为什么同一个方法内,先多申请一些,然后再shrink,能避免多次resize、fgc??所以有点儿好奇你的调用场景

使用时发现的现象:10s 内调了160次resize,双数组大小为40M,相当于10s内产生了160*40M=6400M=6.4G的数组

现象原因:在构建过程中,随着数据增加数组长度不够用需要扩容,如果每次扩容量太少就需要频繁调用resize扩容,而resize会产生废弃的旧的数组,这些数组没有被及时回收堆积起来就会触发fgc。build方法里的resize只是初始化,后续逻辑还会多次调用resize。

解决办法:增加每次resize的大小,避免频繁扩容,减少垃圾的产生,也就避免了fgc

hankcs commented 7 months ago

感谢贡献,我也有类似的concern。

  1. 每次resize2倍,虽然减少了碎片,但增加了内存峰值
  2. resize多少次应该与具体词典大小有关,可否预先给大辞典更大的初始大小?当然具体多少需要做实验总结
  3. 直接在resize内部double size,违反了be explicit的原则
qiangwang commented 7 months ago

@hankcs 这3个点都很有道理,是不是可以提供一个参数出来控制扩容比例(比如resizeRatio)?用户可以自己决定要不要用,也能明确知道对应的影响

qiangwang commented 6 months ago

@hankcs 看看最新的修改怎么样

关于2,给一个更大的初始值对用户来说使用难度会增大,多少合适其实是一个变化的过程,当字典不断增大需要持续调整,而设定一个合适的增长比例就比较简单了,根据用户能接受的内存峰值配置就好