只接受发布货源信息,不可发布违法信息,一旦发现永久封号,欢迎向我们举报!
1064879863
16货源网 > 餐饮行业新闻资讯 > 软件开发 >  为什么方舟编译器使用引用计数垃圾回收,性能却提升了?


为什么方舟编译器使用引用计数垃圾回收,性能却提升了?

发布时间:2019-09-03 09:01:22  来源:网友自行发布(如侵权请联系本站立刻删除)  浏览:   【】【】【
近些年诞生的运行时/VM几乎没有再用RC(引用计数)做GC的了, 这在20多年前就已经成为定论, 想要达到综合能力最好(适用范围广,高性能)还是必须基于trace的GC.RC现在只用于简单的环境,达不
为什么方舟编译器使用引用计数垃圾回收,性能却提升了?

近些年诞生的运行时/VM几乎没有再用RC(引用计数)做GC的了, 这在20多年前就已经成为定论, 想要达到综合能力最好(适用范围广,高性能)还是必须基于trace的GC.

RC现在只用于简单的环境,达不到成熟和完善的先进标准,尤其是在设计泛用的运行时/VM.

"RC能避免STW暂停"只是回避难点的借口而已. 有志气还是应该好好分析以JVM为代表的典型GC发展历程, 从单线程到并行再到并发, 从单一内存池到分代再到分区, 从CMS到G1再到ZGC分别解决了哪些问题,有了哪些改进. 之后再回过头来看RC如果仍然需要, 那才是真正适合的场合(如内存不宽裕的运行环境).

"循环引用"的问题其实并不能简单地完善解决,最终也离不开类似trace的算法. 问题中的"第二个开销",这在单线程环境也许还好, 如果要支持多核并发,那么原子性的引用计数为了所有核的可见性会有不小的开销.

总之, "性能却提升了"很可能只是个"赶英超美"的口号,安卓这十年的优化历程哪有那么容易追的, 如果早点开始做还容易追.

关于RC的部分开源的还不全,还得看更多代码才能确定。

官方稿中没有明确说明性能提升与引用计数之间有联系,文中仅阐述了采用引用计数解决了卡顿问题。

个人推测官方稿所提及的那部分性能提升是省掉了jit编译以及深入安卓app采用更精确的gc时机还有去除jni降低通讯损耗的功劳,与引用计数无关。

个人认为确实有影响,但是问题不大,主要是每次的创建和回收被平均分配到整个执行的各个过程,没有trace gc的统一处理的延时,所以对普通人来说,其感受反而好了。

引用计数不一定开销更大,部分场景RC也有优势,方舟编译器也不可能完全基于单纯的 Naive RC。我不知道方舟编译器开发者到底是怎么想的,现在源码只开放了一小部分,你也无话可说。但是根据官网上的演示代码,我至少可以肯定,写这个演示代码的人连基本的GC常识都没有:

https://www.openarkcompiler.cn/demonstration


懂的自然懂,不懂的只管继续沸腾就是了。

我错怪切图仔了,方舟编译器源码里的samples/rccycletest/RCCycleTest.java就是这么写的:

https://code.opensource.huaweicloud.com/HarmonyOS/OpenArkCompiler/file?ref=master&path=samples%252Frccycletest%252FRCCycleTest.java


没想到还有这么多人看不明白,那我就给出参考代码吧:


落后的 Hotspot JVM 会输出如下内容:

沸腾的「方舟编译器」应该假装输出如下内容:

对于 UI 应用来讲,JVM 的 STW 明明就是很恶心,这个实在是洗不过来吧。

方法的选择要看场景嘛,没有银弹。UI 的话,相对不需要很大的承载量,但是 stw 必须控制在一帧以下。不可否认,JVM 如果想做到这点,心智负担是很大的,它的 GC 虽然承载量大,但是 STW 问题也不能回避呀~~ 而引用计数结合其他方式的话,作为 UI 的体验,应该是比单纯 trace 好的。

JVM 的主要问题是,即使是用 trace 的 gc 中,也少有这么不可控的 STW。我本人是做 infra 的,维护的涉及 JVM 的组件,堆内存稍大,gc 优化就困难得不得了。可以说心智负担极大了。

================= 割 =================

各位大佬的讨论,正丰富了「心智负担大」的论据呀~~ JVM GC 这么多种,还要根据不同的情况做选择,内存还必须预分配,各种参数都要挨个调优,这不是心智负担大什么是心智负担大?没有银弹嘛,RC 不是银弹,JVM 也不是。从架构上来讲,RC 对 UI 更友好,更好优化是肯定的。

远的不说,iOS 比 Android 体验好,ObjC 没有 STW 问题,我感觉至少占 20%。BTW,ObjC 就是 ARC 做(伪)垃圾回收的。

首先要明白引用计数在历史上被取代是因为什么问题?吞吐量上不去,会碰到“墙”。终端用户单进程吞吐量多大?为了pauseless牺牲吞吐量是可以理解的。

既然碰不到吞吐量墙,停顿又变少了,直观上看起来就是更“顺滑”了。

循环引用估计运行时还是会启一个线程去标记销毁,混合式gc也不是什么新概念了,不要大惊小怪。

不过示例里在方法出入口插代码的样子好像蔡徐坤啊。

实践一下

用不同的编译器,编译相同的代码,看看没有比安卓快60%不就知道了,这个肯定要实际测试出来的,而不是拿书本的《编译原理》《操作系统》在那文邹邹地说一堆没用的

垃圾回收算法不断发展,但有三大基本算法是不可或缺的,即引用计数,标记清除,标记复制。

其他更先进的垃圾回收算法都可以拆分成这三种基本算法的组合。

所以华为说他是RC(引用计数),就不要天真的以为华为的GC只有RC,一定是结合了其他垃圾回收算法才可以完整进行垃圾回收的。(目前推测可能和Python的GC算法类似,即部分标记清除算法的变形)

对GC来说,吞吐量和STW问题是两个完全不同的优化目标,为了缓解STW问题提升流畅性而部分牺牲性能(吞吐量)是可以接受的。

这就好像洗澡的时候,水压(吞吐量)小一点是可以接受的,但水时有时无(暂停时间)用户体验就很差了。

华为基于RC做垃圾回收,意味着在循环引用出现不频繁的情况下,(少量的循环引用导致的内存泄露可以放任不管,毕竟安卓系统和APP都是会经常重启的,也可以进入后台后再做全面GC)暂停时间可以控制的很好。

可是如果真正的业务代码不可避免的产生了大量的循环引用,会导致处理循环引用的那部分GC算法频繁运行,依然会导致较大的暂停时间出现,这时候华为这种GC算法会不会反而导致负优化?对于循环引用,方舟编译器支持在代码里做一些注解来辅助编译器处理,以此减少循环引用的出现。如果业务逻辑中包含会导致循环引用的代码,为了优化在方舟编译器环境下的性能表现手动做注解,会不会导致比较严重的心智负担?

而产生循环引用的场景在安卓开发中是否很常见?希望有懂安卓开发的朋友可以答疑解惑。

我觉得关键原因是:如果一个变量不会发生逃逸,那么这个变量使用引用计数的方法来回收,可以比STW这种方式要快。

那个关于引用计数的sample是外包写的么 教教华为正确的搞出循环引用的方式

即便 ARC 在编译时插入了额外代码,它的开销也比一次 STW GC 要小太多。一次 full GC 对于 UI 的流畅性是致命的。而 ARC 在这种场景下可以把内存释放的开销平摊掉。

话说回来你 UI thread 在 60 fps 下会碰到什么吞吐量天花板?

我认为题主的问题属于一个 X-Y 问题——题主其实只是想知道为什么方舟用 RC,由于华为的营销辞令指出【使用 RC 解决卡顿】而导致题主的疑惑变成了【为什么方舟的 RC 比集中管理的 GC 更快】。事实上,无论如何 RC 肯定都是更慢的。这一常识性的知识在广大非入门级程序员的脑海里已经根深蒂固,导致大家看到华为这种明显是糊弄非技术人员的营销,肯定心里不爽(我也不爽。老李的群已经喷过了)。

事实上,我们可以把眼光转向另一移动端应用的巨头——iOS。iOS 平台上的编程语言是怎么 GC 的呢?我们可以看看这个问题:iOS: Garbage collection。现在大家知道了吧?方舟在 Android 上使用 RC 可以被我们视作是对标 iOS 的行为,站在这个视角下是不是觉得使用 RC 容易原谅得多了呢?如果要在方舟编译出来的程序里嵌入复杂的 GC 系统,会不会不必要地增大编译出来的 binary 尺寸?再考虑另一方面,如果他们把工作重心放在 GC 上,会不会拖累他们在 reflection analysis,alias analysis 上的工作进度呢?或许他们团队就认为 GC 的重要性低于其他的部分吧。

至于那些 bug,等他们程序员慢慢修呗,这又不是最终的版本,开源世界是怎样的?遇到 bug,你应该自己去修,或者客客气气地向官方反馈,这才是你混社区应有的态度(参考我的回答:如何在GitHub上做一个优秀的贡献者?)。虽然方舟的代码对于我这种有点点编译器底子的人来说,逻辑还是很清晰的,如果你真要说你看不懂的话,我只能断定你是个菜鸡了。但是平心而论,就凭方舟的代码这软件工程水平(参考那些喷代码中的 C++ 基本功的回答。此处我就略过了。而且如果你真的看过这个代码,你会觉得这个作者的面向对象程序设计经验严重不足,这也是为什么我不想更新前面的回答了,解释起来好难受()),走形式验证会很痛苦,出 bug 是非常非常非常正常的事了,我们能不能对自己的同行宽容一些呢?

责任编辑:
热门阅读排行
© 16货源网 1064879863