当前位置:首页 > 每日看点 > 正文内容

无gc语言如何处理内存碎片问题?

卡卷网1年前 (2024-12-30)每日看点201

首先你要明白回收语言性能不手动系差,甚至在各种需要作大量指针的程序更好。

这是因为两点。

<>gc语言申请释放内存的速度远高于malloc/free

内存申请是这样的,gc只需要umpallocate,freelist要考虑得就多了。各种各样的allocator(如最经典的freelist),在malloc的时候,需要搜索一个数据结构来寻找足够大的空间。这期间,搜索需要耗时,并且这个数据结构往往没有好cachelocality,导致在memorylatency越来越重要的今天成为越来越严重的瓶颈。同时,不止freelist没locality,返回的指针也没locality-你连续malloc很可能得不到连续的。这时候如果你访问这些结果,你需要进行多次cachefetch而不是一次。

作为对,markcopy/markcompact的gc的allocator只是一个int,代表当时内存消耗量,每次malloc只是单纯的把size加上去,然后返回上一个消耗量,转为指针则可。

而另一方面,这份极简实现导致这两无法实现free,只能通过gc一次回收大量资源,通过atching降低内存消耗。

<>rc的时间消耗远高于tracing的性能消耗

rc需要你每次使用对象的时候检查refcount并且对此进行增减。如果你在写多线程程序,refcount甚至需要同步,耗费额外的性能。作为对,如果是markcopygc,并且堆大小为livememory*2的话,每次markcopy需要作LiveMemory多的对象,然后释放HeapSize-LiveMemory=LiveMemory多的内存-换句话说,只需要一次copy则可完全回收(可以看到,越大的heapsize需要做的gc越小,但是吃的内存越多。如何在时空之间取舍呢?可以看OptimalHeapLimitforReducingrowserMemoryUse)。这点跟传智慧(GC慢,RC快),是完全反过来的。道理很明显-如果RC更快,为什么JVM不用RC内存,外搭环检测器呢(python就这样做的,然后python性能有目共睹)?事实上,Stevelackn就做过一个测量GCvsRC的工作,MythsandRealities:ThePerformanceImpactofGarageCollection。这个工作的测量结果是,GC往往会带来10%左右的开销,但是RC的开销是30%~50%。

<>那问题来了,既然GCmalloc/free也RC优秀,为什么Ja没C++快?

这是计算机领域的一个巨大归因谬误。我们先来看看这段代码:

importja.util.*; recordPoint(intx,inty){} //... intSumX(List<Point>points){ intsum=0; for(Pointp:points){ sum+=p.x(); } retnsum; }

这段Ja代码运行的时候计算机在具体执行什么作?

首先,Point被oxed了。oxing导致你可以快速把一个对象到处传(只需要复制指针而无需复制具体对象),但是会造成每次引用oxed具体内容都需要fetch远处的memory。在函数式语言中这个问题更糟糕:这时候,数据往往被储存于各种各样的链表中,而遍历就除了unox外还需要爬链表的指针,于是一次循环需要两次memoryfetch。

C++里面呢?同样的任务,会被存在vector<pair<int,int>>内。主流计算机的cacheline是64yte,也就可以存4个这样的对象,于是四次循环一次memoryfetch。同时,在性能关键的情况下,这列表可以用pair<vector<int>,vector<int>>保存,俗称的structofarrayoverarrayofstruct[1]。然后,由于sumofX只需要触碰X,所以是八次循环一次memoryfetch,对着函数式编程的方案,有着16倍的memoryfetch开销-一个数量差!现实中,情况往往没这么极端,但是一个小倍数依然是很大的差距。

<>同时,C++也并不用RC

我们观察上述代码的C++形式:

structPoint{ intx; inty; }; intSumX(conststd::vector<Point>&points){ intsum=0; for(constPoint&p:points){ sum+=p.x; } retnsum; }

可以注意到,

    vector手动了内部Point的内存,而不是RC传入SumX的是一个引用,而不是RCiterate用的又是一个引用,而不是RC

也就是说,大部分C++代码的内存并不是RC,而是stl容器手动,以及利用程序结构LIFO特性传引用。这导致尽管RC有很高的overhead,但是只要你用得不多,还是可以的。

当然,反过来说,用得多的情况,如编译器(指针满天飞),GC语言可以取得没GC语言更好的性能(因为他们需要很多RC)

题目中的程序描述(频繁malloc/free小对象,同时面条代码翻译表明大概用上了RC),正是GC语言的最优发挥场所,打不过也不奇怪。

如果要优化性能,可以试试看用arena内存。如果生命周期不确定并且一定要及时释放,那要考虑自己实现一个简单的markcopyGC了,可以试试看Cheney'salgorithm。(当然,也可以更简单的换回Ja)。

<>如果要在无GC语言里面解决内存碎片,怎么办?

Mesh:CompactingMemoryManagementforC/C++Applications就是一个带有反碎片化功能的malloc/freeallocator。听上去很矛盾-你既然不知道指针都在那,你怎么可以通过move来compact呢?

因为allocator底层还有东西。你allocate到的内存并不是‘正的’,底下还有TL把这些虚拟变成物理。那我们考虑两个页面,其中被用到的互不相交,这时候我们可以用一个物理页来表示这两个虚拟页,从而消除碎片化。

十分神奇的是,直觉告诉我,这样‘刚刚好’的页面不好找,但是他们用组合数学证明了这样的页面配对有很多,而且找起来很快!

扫描二维码推送至手机访问。

版权声明:本文由卡卷网发布,如需转载请注明出处。

本文链接:https://www.kajuan.net/ttnews/2024/12/5984.html

分享给朋友:

相关文章

小米14 Pro和Redmi K70Pro怎么选?

小米14 Pro和Redmi K70Pro怎么选?

两款手机都使用了最新的骁龙8Gen3旗舰芯片,性能都是顶级,但是两款手机定位不同,卖点不同,红米K70 Pro定位主打性能的旗舰入门手机,小米14Pro定位旗舰中高端手机。具体根据个人需求与预算来选择:两款手机的相同、相似点:都使用了骁龙8...

Layui 不更新了么?

Layui 不更新了么?

layui2.8已经于今天正式发布了,新增优化了大量特性,这里按照layui更新日志的模块结构,详细为你一一介绍。基础风格调整新版调整主色调为#16baaa,在原有的墨绿基础上赋予了清新。更简单的构建构建代码更简单,除字体外,只有js和cs...

为什么我们一直在给B站充大会员但B站却一直处于亏损状态?

我讲一下离谱的真相吧,欢迎喷我。很多人都觉得B站在赶走人才,赶走优秀的长视频创作者,也觉得知乎在这么做,是没错的。确实在这么做。而原因很简单。只有影响力很大的KOL才有商业价值。(KOL是指“关键意见领袖”)而你说你是人才?对不起,人才不赚...

数字人民币为什么又不火了?

我完全不懂行。我一开始以为,数字人民币,是对我银行里的每一分钱,都赋予一个独一无二的数字编码。我要用一块钱买矿泉水,它就从我的存款中随机选取一百个一分钱,组合成一块钱,支付给商家。我花一百块钱吃饭,它就随机选取一万个一分钱,组合成一百块钱,...

有哪些网站,一旦知道,你就离不开了?

有哪些网站,一旦知道,你就离不开了?

这六个网站,一旦用过,基本上是离不开了。都是我超爱的一些网站,基本上每天都用。1 地图生成器第一个,我要给大家推荐的是地图生成器。可以下载到各省,各市,各县的svg格式的地图素材。这些素材导入PPT中都是可以编辑的。可以单独更改颜色和轮廓。...

只有我一个人后悔升级鸿蒙next吗?

只有我一个人后悔升级鸿蒙next吗?

我有一台mate 60 pro,第一时间升级了“纯血鸿蒙”。虽然功能并不完善,甚至有些简陋,但是我非常~非常不后悔升级鸿蒙next系统。因为.... 这就是一款“大型养成系游戏“,给我平淡的生活提供了源源不断的情绪价值。我每天特别...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。