当前位置:首页 > 每日看点

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

卡卷网2年前 (2024-12-30)每日看点294

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

这是因为两点。

<>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

分享给朋友:

相关文章

为什么大家不再提 5G 了?

现在看来,只有美国那种5g的思路是对的。 美国的运营商一开始就发现5g和4g并没有质的飞跃,无非就是提升频率/降低穿透力/提升带宽的故事。而美国运营商又是自负盈亏,因此一开始就仅在人口高密度地区或富裕地区布置5g。 虽然说人家4g也菜,但是…

WordPress建站同时面向B端和C端,有什么好的解决方案?

这个很容易实现呀,只不过需要自己开发,整体用权限管理就可以实现了,B端和C端是不同用户权限,C端能看到的菜单入口和B端不一样就行了。技术层面实现没问题的,只不过就是看你们的技术能力和投入了 ,这样的需求应该没有现成的开源插件。只能找人定制开…

如何看待台积电,三星相继停供大陆7nm及更先进芯片?

在这个事出来之前,我就看到过一个说法,两家Foundry可以在中东建厂,让中东的Fab去干“脏活”。本质上是国内企业搞几个中东的代理人,装作是中东的初创Fabless企业去下单,人家Foundry大概率睁一只眼闭一只眼,只管数钱。然而,紧接…

在 Kubernetes 中,Service 的实现原理是什么,它是如何实现服务发现的?

行,问的这个问题挺有意思,Kubernetes 里 Service 是怎么实现的,服务发现是怎么回事,咱就直说了。这事儿看起来挺玄乎,但掰开揉碎了讲,也就那么回事。你得把这事儿想得简单点,别一上来就被啥术语吓住了——其实全是些搬砖的套路。…

如何评价小米14这款手机?

如何评价小米14这款手机?

本来小米 14 和 14 Pro 是打算放一起拆的,但是因为时间关系,实在凑不到一起了。所以今天给大家补一篇详细的图文拆解,基本信息都有了,如有遗漏可以在评论区留言。 双卡上下放置,卡托材质为金属 + 塑料,内侧有防尘防水的胶圈。…

你怎么看待软件测试这个工作的?

你怎么看待软件测试这个工作的?

先说一个插曲:上个月我有同学在深圳被裁员了,和我一样都是 软件测试,不过他是平安外包,所以整个组都撤了,他工资和我差不多都是14K。现在IT互联网已经比较寒冬,特别是软件测试,裁员先裁测试,这几乎都是定律。我最近看了某音很多应届生以及去年毕…

发表评论

访客

看不清,换一张

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