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

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

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

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

这是因为两点。

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

分享给朋友:

相关文章

为什么大家都说手机性能永远超不过PC?

最新的天玑9400牛逼吧,堪称PC级CPU,测试成绩16W功耗能跑9500分,1.8W能跑3000分,GPU也差不多是这个情况。 手机电池一般是4000-5000毫安时,电压3.7V。 也就是说,手机正常满载5W功耗下,这个电池能支持运行4…

MacOS真的比Windows流畅吗?

我现在公司配的机器,配置是绝对的大古董了 惠普z230sff薄塔 cpu只是个4770,没错不是4790k,4770全核睿频只有3.8g 显卡更是古董,k600,已经结束驱动更新支持了,显存仅1g,跑分跑不过13代uhd核显 内存是加到16…

我怎么也无法理解网络游戏为什么会有外挂?

我怎么也无法理解网络游戏为什么会有外挂?

因为你把服务器想象成了无所不能的上帝;但在我们程序猿眼里,服务器不过是一个黑大傻粗的计算器。 比如说,我们在某个位置打开一个宝箱: 那么,你觉得,程序背后应该做了些什么呢? 一、天真的玩法天真的程序猿会觉得,啊,这事简单!我就告诉服…

买了华为的用户真的不觉得卡吗?

不知道哪一年开始,几乎所有,几乎,所有。 几乎所有的数码区,手机区up主,测手机流畅度的操作变成了 桌面启动app看动画 打开x个app数时间 而更早之前,我记得是有很多up主,测试手机流畅度是测试应用内信息流滑动的。 我倒不是怀疑各位手机…

真实的FPGA开发工作是以调用IP核为主吗?

真实的fpga以背锅为主。 没有开玩笑,正好今天遇到一个问题,做视频图像方面的,用的lattice片子,bram资源用了100%还不够用,怎么办,综合的时候把slice资源也给用了100%,这意味着布局布线非常难布,sdram的时钟肯定跑不…

为什么百度搜索引擎越做越差?

说一个最近刚发生的, 昨天孩子学校要求打印《滕王阁序》全文带到学校去晨读,我想找一个带拼音和注释的版本,我在百度上足足找了半个小时,愣是没找到一个可以直接下载的文件,全部都要注册收费,有的文件下载居然要10块钱,我心想《滕王阁序》是王勃写的…

发表评论

访客

看不清,换一张

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