首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >神能道自愈障碍

神能道自愈障碍
EN

Stack Overflow用户
提问于 2020-09-29 17:27:59
回答 1查看 86关注 0票数 0

这个标题说明了一切--这些自我愈合的障碍是什么,为什么它们在神兰多阿2.0中很重要?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-09-29 17:27:59

这一解释将在第一部分第二部分上传回我试图在Shenandoah 2.0上提出的一些答案。

要真正回答这个问题,我们需要了解load reference barrier是如何实现的,以及GC cycle一般是如何工作的。

当某个GC cycle被触发时,它首先选择垃圾最多的区域;也就是说:集合中的对象非常少(这在将来会很重要)。理解这个主题的最简单的方法是通过一个例子。假设这是一个现在存在于某个区域的计划:

代码语言:javascript
复制
refA refB            
    |               
---------
|  mark |                    
---------          
| i = 0 |          
| j = 0 |          
--------- 

区域中存在一个对象,并且有两个引用指向它:refArefBGC启动,这个区域被选择为垃圾收集。同时,应用程序中有一些活动线程试图通过refArefB访问该对象。因为这个对象在某个时候是alive,所以它需要被疏散到一个新的区域( mark-compact阶段的一部分)。

因此:GC是活动的,同时,我们通过refA/refB阅读。当我们完成这一读取时,我们将步进load-reference-barrier,实现这里。注意它内部有一些“过滤器”(通过一堆if/else语句)。具体地说:

  • 它检查“撤离是否正在进行中”。这是通过线程本地标志来完成的,该标志是在疏散第一次开始时设置的。让我们假设答案是:是的。
  • 它检查我们当前操作的对象是否在“集合集”中。这意味着它目前被标记为活着。让我们假设这也是“是”。
  • 最后一次检查是要找出这个对象是否已经被“复制”到另一个区域(它已被疏散)。让我们假设这个问题的答案是“否”,即:obj == fwd

在这个时候,发生了一些事情。首先创建一个副本,然后mark 成为前进者

代码语言:javascript
复制
    refA refB            
        |               
 --------------      ---------
 |  forwardee | ---- | mark |            
 --------------      ---------    
    | i = 0 |        | i = 0 |  
    | j = 0 |        | j = 0 |  
    ---------        ---------

只有在代码的后面,才会更新refArefB,以指向新的(复制的)对象。但这意味着一件有趣的事情。这意味着,在refArefB被实际指定为指向新对象之前,它们当前指向的对象位于“集合集”中。因此,如果GC是活动的,即使已经建立了forwardeeload-reference-barrier仍然需要做一些工作。

因此,Shenandoah背后的非常聪明的人说:为什么不在forwardee建立之后(或者当forwardee已经因为其他引用而闻名时)立即更新那里的引用呢?这正是他们所做的

让我们假设我们回到最初的绘图:

代码语言:javascript
复制
refA refB            
    |               
---------
|  mark |                    
---------          
| i = 0 |          
| j = 0 |          
--------- 

再一次,我们“启用”所有过滤器:

  • 有一个通过refA读取的线程
  • GC是活动的
  • refArefB背后的对象是活动的。

这就是“自我治愈障碍”将会发生的情况:

代码语言:javascript
复制
       refB             refA
        |                |
 --------------      ---------
 |  forwardee | ---- | mark |            
 --------------      ---------    
    | i = 0 |        | i = 0 |  
    | j = 0 |        | j = 0 |  
    ---------        ---------

区别是显而易见的:refA被移动到通过CAS指向新对象的现场。如果要通过refA再次读取(GC仍然处于活动状态),这将导致一个更快的加载引用屏障执行。为什么?因为refA指向一个不在“集合集”中的对象。

但这也意味着,如果我们通过refB阅读并看到fwd != obj --代码可以完成同样的任务并在适当的地方更新refB,此时第一次读取是通过refB进行的。

据知情人士说,这提高了业绩,我相信他们。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64124676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档