遍历灰色对象,将灰色对象引用的对象(备注:这里指的是灰色对象引用到的所有对象,包括灰色节点间接引用的那些对象)也变成灰色对象,然后将遍历过的灰色对象变成黑色对象。...,于是将 A、F 从变为灰色对象。...GC 继续扫描灰色对象,会将灰色对象的节点中引用的节点也变为灰色对象,A 节点引用的节点B、C、D 会被变为灰色对象,接着 A 的所有子节点遍历完毕,便会变为黑色对象,而 F 节点没有子节点,也会变为黑色对象...GC 会循环遍历灰色对象,直到灰色对象之中没有节点为止,在本例中,发现B、C、D 都没有子节点是白色,便将B、C、D 都变为黑色对象。 剩下E、G、H 为白色对象,GC 便进行回收这些白色对象。...上面的垃圾回收结束之后,GC 会在进行一步操作,也就是将黑色对象重新变色成白色对象,供下一次垃圾回收使用。
假设现在有白、灰、黑三个集合(表示当前对象的颜色),其遍历访问过程为: 初始时,所有对象都在【白色集合】中; 将 GC Roots 直接引用到的对象挪到 【灰色集合】中; 从灰色集合中获取对象: 3.1...将本对象引用到的其他对象全部挪到 【灰色集合】中; 3.2. 将本对象挪到【黑色集合】里面。 重复步骤3,直至【灰色集合】为空时结束。...此时切回 GC 线程继续跑,因为 E 已经没有对 G 的引用了,所以不会将 G 放到灰色集合;尽管因为 D 重新引用了 G,但因为 D 已经是黑色了,不会再重新做遍历处理。...黑色对象重新引用了该白色对象;即黑色对象成员变量增加了新的引用。...三色标记法与现代垃圾回收器 现代追踪式(可达性分析)的垃圾回收器几乎都借鉴了三色标记的算法思想,尽管实现的方式不尽相同:比如白色/黑色集合一般都不会出现(但是有其他体现颜色的地方)、灰色集合可以通过栈/
黑色对象表示活跃的对象,它引用的对象都被扫描 步骤 将所有对象标记为白色节点 从根节点开始,将第一次遍历到的节点标记为灰色 遍历灰色节点,将遍历到的白色节点标记为灰色,并把该灰色节点标记为黑色 循环这个过程...直到不存在灰色节点,回收所有的白色节点 图解 将对象标记为白色节点 从根节点遍历得到灰色节点 遍历灰色节点,将灰色标记为黑色,遍历到的节点标记为灰色 重复操作 直到没有灰色节点...为了保证栈的运行效率,屏障只对堆上的内存对象启用,栈上的内存会在GC结束后启用STW重新扫描。 插入屏障 使程序满足强三色不变性,当白色节点被黑色节点引用时,将白色节点变为灰色,从而保留这个节点。...缺陷:如果白色节点被栈上的黑色节点引用,不会触发插入屏障,最后还是会被删除。 删除屏障 使程序满足弱三色不变性,当白色节点的引用被删除时,将白色节点变为灰色,从而保留这个节点。...Go1.8混合写屏障 概念 解决插入写屏障和删除写屏障在结束时需要STW来重新扫描栈带来的性能问题 步骤 GC开始将栈上的对象全部扫描并标记为黑色 GC期间任何在栈新创建的对象都标记为黑色 堆上被删除的对象标记为灰色
概念 当被问到垃圾回收算法的时候,大多数人都知道三种回收算法,标记-清楚,标记-复制,标记-整理,但是标记的过程是如何的呢?在并发型标记的时候是怎么对对象图进行遍历的?...三色标记法 :在三色标记法中存在三种颜色,白色,灰色,黑色 白色:表示对象尚未被垃圾收集器访问过。 灰色:表示该对象已经被垃圾收集器访问过,但是这个对象上至少还存在一个引用还没有被扫描过。...,程序会因此发生错误 经过Wilson的证明当且仅当以下两个条件同时满足的时候才会产生“对象消失”的问题,即把原来应该是黑色的对象被错误标记为白色: 插入了一条或多条从黑色对象到白色对象的引用 删除了全部从灰色对象到该白色对象的直接或间接引用...解决办法 增量更新 增量更新破坏的是第一个条件,当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描后再将这些记录过的引用关系中的黑色对象为根重新扫描一次,这样可以简化理解为黑色对象一旦插入新的指向白色对象它就变为灰色对象了...CMS就是基于增量更新来实现的 原始快照 原始快照破坏的是第二个条件,当灰色对象要删除指向白色对象的引用关系时,就要将这个要删除的引用记录下来,在并发扫描结束之后,再将这些记录过的引用关系中的灰色对象为根
step 函数 有时我们需要通过着色器来表现图形,那如何通过坐标控制颜色值的输出,得到基本图形呢?...想要展示一个半径为 r 的黑色圆形,只需要计算 像素点 距原点距离 len , 对于所有 len <= r 的像素点着为黑色;反之着为白色: 这个逻辑由下面的 circle 方法进行处理:当 len <...多个圆形联合 现在想一个小问题:如何将圆形呈白色,周围是黑色呢?...很简单,用 1 - step(r, len) 即可,这样原来的黑色 1 就会变为白色 1-1 = 0 ; 原来的白色 0 就会变为白色 1-0 = 1: 根据 step 的作用,不难推出: 1 - step...从 对每个像素操作 的视角来看,返回 1 表示该像素点是白色,返回 0 表示黑色; c0 + c1 表示每个像素点的值是两个圆的结果累加值。
灰色:对象还在标记队列中等待被标记。 黑色:对象已被标记,gcmarkBits 对应位为 0,该对象将会在本次 GC 中被回收。 三色标记: 新创建的对象,默认标记为白色。...从根节点开始遍历所有白色对象,将遍历到的对象的颜色由白色改为灰色。 将灰色对象作为根节点开始遍历所有白色对象,将遍历到的对象的颜色由白色改为灰色,并将作为根节点的灰色对象的颜色由灰色改为黑色。...循环往复,直到所有灰色对象的颜色都变为黑色。 将剩余的白色对象全部清除。 三色标记的缺点: 一个不被灰色对象可达的白色对象,如果被一个黑色对象引用,将会造成该白色对象丢失的问题。...强三色不变性,即强制性不允许黑色对象引用白色对象; 弱三色不变性,即黑色对象可以引用白色对象,但是必须满足一个条件,该白色对象必须有灰色对象对它的直接引用,或者是可达链路中包含灰色对象。...混合写屏障: 后续无需 STW,GC 在首次执行时,先将栈上的所有对象都标记为黑色。 GC 在执行过程中,在栈上新创建的对象,默认被标记为黑色。 将被删除的对象标记为灰色。
Go v1.5 带 STW 的三色并发标记法 三色标记法,此时依旧需要 STW 将所有对象归纳成三种颜色,三色概念的抽象如下: 白色:可能是垃圾的对象 灰色:存活对象,但子对象待考察 黑色:存活对象 下面描述...GC 的过程 一开始将所有对象视为白色 从根对象开始考察可达对象,将可达对象本身记为灰色 遍历灰色集合,将灰色对象本身记为黑色,并将其子对象记为灰色 重复第 3 步,直到灰色集合没有对象,此时所有的黑色对象为存活对象...一开始所有对象都是白色 从根对象开始考察,将第一个对象记为灰色 之后遍历灰色集合,将灰色对象记为黑色,并将其子对象记为灰色 重复上述步骤,直到灰色集合清空,此时黑色对象就是存活对象,白色对象就是垃圾对象...这样就会导致当再次遍历灰色对象集合时,将对象2移动到黑色集合之后,由于对象2不再持有对象3的引用,所以不会再考察对象3,同时由于对象4已经是黑色的考察过的对象,也不会再次考察对象3,结果就是对象3被记为白色...如此引出强弱三色不变性: 强三色不变性:黑色对象不可以指向白色对象,只可以指向灰色对象或者黑色对象; 弱三色不变性:黑色对象指向的白色对象必须包含一条从灰色对象经由多个白色对象的可达路径 插入屏障和删除屏障
在评估期间,无心插柳地探索到一个新技术,就是关于PPT课件统一更改字体颜色和页面背景颜色的问题。...我想大家都遇到过类似情况,就是有时想把PPT打印出来备课用,可以在纸上写写画画对课件做标注之类的,但若是你的PPT原本是深色背景,如我有时喜欢用深蓝背景、白色字体,这样打印时很费墨的,因为打印出来整张纸背景都是深灰色或黑色...你的所有PPT都变成了黑白灰色,包括图片,所有页面背景是正常白色,所有字体是黑色(包括链接),原来你用的设计模板的颜色样式这时完全不起作用了!放心去打印吧!...另外,如果你不希望打印原来模板的背景图形,可以在任一页面无内容的空白处点击右键,选择背景,选择忽略母版的背景图形,再选择全部应用即可,但这时就会改变你的原文件,不过没关系,打印完后,再改回来就是了。...打开你要打印的PPT课件,在任一页面无内容的空白处点击右键,选择幻灯片配色方案,你可以点击选用标准配色方案中有黑白灰三色的方案;也可自定义配色方案颜色,把所有背景色变为白色、字体变为黑色等。
变暗模式导致比背景色更淡的颜色从结果色中去掉,如下图,浅色的图像从结果色中被去掉,被比它颜色深 的背景颜色替换掉了。...其实就是将 基色与混合色相乘,然后再除以255,便得到了结果色的颜色值,结果色总是比原来的颜色更暗。...当任何颜色 与黑色进行正片叠底模式操作时,得到的颜色仍为黑色,因为黑色的像素值为0;当任何颜色与白色进行正片叠底 模式操作时,颜色保持不变,因为白色的像素值为255。...在强光模式下,当前图层中比50%灰色亮的像素会使图像变亮;比50%灰色暗的像素会使图像变暗,但当前 图层中纯黑色和纯白色将保持不变。...与强光模式相比,线性光模式可使图像产生更高的对比度,也会使更多的区域变为 黑色或白色。 18,点光混合模式 点光混合模式其实就是根据当前图层颜色来替换颜色。
你可以设置一个阈值,其中低于此阈值的所有值都将变为黑色,高于此阈值的所有值都将变为白色。 执行 现在你已经有了所有你需要的东西。...,我只是通过将位于此范围内的所有数据统一到一个强度,在此迭代中简单地转换我想要轮廓(高亮)的灰色范围(强度)。...我将所有其他强度转换为黑色(包括更大和更小的强度)。 第二步我对图像进行阈值处理,以便只有我想要轮廓的颜色现在显示为白色而其他所有颜色都转换为黑色。...在应用此步骤(阈值处理)之前,下面的图像将是相同的,除了白色环将变成灰色的(第10个灰度级的灰度强度(255-15 * 10)) ?...左图:转换为HSV后的图像(1) 右图:应用模板后的图像(颜色统一)(2) ? ? 左图:从HSV转换为灰色后的图像(3) 右图:达到阈值的图像,最后一步(4) ?
三色标记算法将程序中的对象分成白色、黑色和灰色三类: 白色对象 — 潜在的垃圾,其内存可能会被垃圾收集器回收; 黑色对象 — 活跃的对象,包括不存在任何引用外部指针的对象以及从根对象可达的对象,垃圾回收器不会扫描这些对象的子对象...第二步, 遍历根节点集合里的所有根对象,把根对象引用的对象标记为灰色,从白色集合放入灰色集合。 ?...第三步, 遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合 ? 第四步:重复第三步, 直到灰色集合中无任何对象。 ?...; 弱三色不变性 — 黑色对象指向的白色对象必须包含一条从灰色对象经由多个白色对象的可达路径 屏障技术 垃圾收集中的屏障技术更像是一个钩子方法,它是在用户程序读取对象、创建新对象以及更新对象指针时执行的一段代码...,除了引入混合写屏障之外,在垃圾收集的标记阶段,我们还需要将创建的所有新对象都标记成黑色,防止新分配的栈内存和堆内存中的对象被错误地回收,因为栈内存在标记阶段最终都会变为黑色,所以不再需要重新扫描栈空间
黑色对象 — 表示对象已经被垃圾收集器访问过,且这个对象的所有引用都已经被扫描过,黑色的对象代表已经被扫描过而且是安全存活的,如果有其他对象只想黑色对象无需再扫描一遍,黑色对象不可能直接(不经过灰色对象...三色可达性分析算法大致的流程是(初始状态所有对象都是白色): 1.从GC Roots开始枚举,它们所有的直接引用变为灰色(移入灰色集合),GC Roots变为黑色。...2.从灰色集合中取出一个灰色对象进行分析: 将这个对象所有的直接引用变为灰色,放入灰色集合中; 将这个对象变为黑色。 3.重复步骤2,一直重复直到灰色集合为空。...上述伪代码非常好理解,当黑色对象(slot)插入新的指向白色对象(ptr)的引用关系时,就尝试使用shade函数将这个新插入的引用(ptr)标记为灰色。...总结来说主要有这几点: GC开始将栈上的对象全部扫描并标记为黑色; GC期间,任何在栈上创建的新对象,均为黑色; 被删除的堆对象标记为灰色; 被添加的堆对象标记为灰色。
黑色的对象代 表已经扫描过,它是安全存活的,如果有其他对象引用指向了黑色对象,无须重新扫描一遍。黑色对 象不可能直接(不经过灰色对象)指向某个白色对象。...灰色:表示对象已经被垃圾收集器访问过,但这个对象上至少存在一个引用还没有被扫描过。...三色标记过程 标记过程: 在 GC 并发开始的时候,所有的对象均为白色; 在将所有的 GC Roots 直接应用的对象标记为灰色集合; 如果判断灰色集合中的对象不存在子引用,则将其放入黑色集合,若存在子引用对象...,分别有两种解决方案:增量更新(Incremental Update) 和原始快照(Snapshot At The Beginning, STAB) 增量更新 增量更新要破坏的是第一个条件,当黑色对象插入新的指向白色对象的引用关系时...这可以简化理解为,黑色对象一旦新插入了指向白色对象的引用之后,它就变回灰色对象 了。
三色标记算法指的是将所有对象分为白色、黑色和灰色三种类型。...黑色表示从 GCRoots 开始,已扫描过它全部引用的对象,灰色指的是扫描过对象本身,还没完全扫描过它全部引用的对象,白色指的是还没扫描过的对象。...但仅仅将对象划分成三个颜色还不够,真正关键的是:实现根可达算法的时候,将整个过程拆分成了初始标记、并发标记、重新标记、并发清除四个阶段。...我们经过分析可以知道,漏标问题要发生需要满足如下两个充要条件: 有至少一个黑色对象在自己被标记之后指向了这个白色对象 所有的灰色对象在自己引用扫描完成之前删除了对白色对象的引用 只有当上面两个条件都满足...那么我就把这个黑色对象的引用记录下来,在后续「重新标记」阶段再以这个黑色对象为跟,对其引用进行重新扫描。通过这种方式,被黑色对象引用的白色对象就会变成灰色,从而变为存活状态。
这一设计明显不同于当今大多数“企业级”垃圾收集器,我们认为它非常适合现代硬件的特性和现代软件的低延迟需求。 三色收集器 在三色收集器中,每个对象都是白色、灰色或黑色,我们将堆视为相互连接的对象图。...GC周期开始时,所有对象都是白色。GC访问所有根对象(如全局变量和栈上的对象),将它们标记为灰色。然后,GC选择一个灰色对象,将其变为黑色,并扫描其中的指针。...扫描发现指向白色对象的指针时,将该对象变为灰色。这一过程重复进行,直到没有更多的灰色对象为止。此时,白色对象被认为是不可达的,可以被重用。...⚙️ 写屏障与简化 为了维护黑色对象不指向白色对象的不变性,引入了写屏障,这是一个由变异器(mutator)在堆中修改指针时运行的小函数。...Go的写屏障在当前为白色的可达对象上涂上灰色,确保垃圾收集器最终会扫描它。 ️ GOGC:单一调节旋钮 Go为了保持简洁,提供了一个名为GOGC的单一调节旋钮。
大家好,又见面了,我是你们的朋友全栈君。 如果学C语言久了,难免会对弹出的黑窗口感到厌烦,那这时候如果能改一下黑窗口的背景颜色和字体颜色,也许会给自己一个好一点的心情。...二、标准库定义了好多的颜色常量,不过都很长不好记,我们先来记一下常用的,简单地常量值代表的颜色; 0 = 黑色 1 = 蓝色 2 = 绿色...3 = 湖蓝色 4 = 红色 5 = 紫色 6 = 黄色 7 = 白色 8 = 灰色...,我们就可以直接调用system(“color 07”)函数来改变背景色和字体色,其中,”color 07″中的0和7代表的是两个数字,上面第二点有说到,0是黑色,7是白色,这是调试窗口的默认颜色,我们可以将...(STD_OUTPUT_HANDLE)作为SetConsoleTextAttribute函数的第一个变量的意思了,有兴趣的可以去详细地查一下。
一、PHP 中的引用计数 1.1 如何确定垃圾 原理: 给对象添加一个引用计数器,每当有一个地方引用它,计数器的值就加一。每当有一个引用失效,计数器的值就减一。...步骤一: 遍历垃圾回收器的 buffer 缓冲区,把 value 标为灰色,把 value 的成员的 refount-1,标为白色。...步骤三: 遍历垃圾回收器的 buffer 缓冲区,将 value 为非白色的节点从 buffer 中删除,最终 buffer 缓冲区中都是真正的垃圾。...PHP 用了一套自己的算法来解决因循环引用而产生垃圾的问题,这套算法可以简单理解为先把可疑垃圾的引用计数减一来进行测试,如果引用计数确实等于 0 ,则标记颜色为黑色,后续一起清理。...PHP 垃圾收集中总共用到了三种关键颜色:白色- 垃圾,黑色- 非垃圾,紫色- 防止重复插入。 - END -
白色:尚未被GC访问过的对象,如果全部标记已完成依旧为白色的,称为不可达对象,既垃圾对象。 黑色:本对象已经被GC访问过,且本对象的子引用对象也已经被访问过了。...漏标-读写屏障 一个本应该不是垃圾的对象被视为了垃圾,如果误清理了正在被使用的对象,那肯定会出现问题。那么如何解决这个问题呢? 出现这个问题的主要原因是,一个对象从被B引用,变更为了被A引用。...2.1 增量更新 增量更新是有重新标记的过程的,当黑色对象新增一个白色对象的引用时,就通过写屏障将这个引用关系记录下来。...然后在重新标记阶段,再以这些引用关系中的黑色对象为根,再扫描一次,以此保证不会漏标。 ...要实现也很简单,在重新标记阶段直接把A对象(和其它有相同情况发生的对象)变为灰色,放入队列中,再来一次枚举过程。
此外,纯黑和纯白的高对比度也会造成视觉疲劳,因此微信的深色模式中,使用了浅灰色作为字体颜色,既能保持清晰显示,又降低了对比度,减轻了用户的阅读负担。...如消息图标会从笑脸切换为休息的状态,这种具有趣味性的设计,也会拉近用户与产品之间的距离。 豆 瓣 普通模式下的豆瓣APP背景色为纯白色,白天看偶尔都觉得有些刺眼,更不用说睡前必刷豆瓣的用户有多煎熬。...知乎在设计夜间模式时,知乎采用了主色调蓝色+深灰色的搭配,深蓝和灰色作为背景,展示出的效果既有强烈的对比,又摆脱了深色的压抑感。 与豆瓣不同,知乎的文本颜色选择了对比度更低的灰色,通过字重进行区分。...在设计深色模式时,除了背景颜色尽量使用深灰色以外,还需要确保绝大部分区域保持深色,尽可能使用数量有限的色彩。把握好对比度和饱和度,才能设计出舒适的深色模式。...从上述APP设计案例中,我为大家总结了以下几点建议以作参考: 1.避免使用纯黑色; 2.避免使用高饱和度的颜色; 3.文本颜色选用高亮色,但不宜使用纯白; 4.做好情感化设计; 5.注意结构和层次感;
这样三种不变性所定义的回收过程其实是一个波面不断前进的过程,这个波面同时也是黑色对象和白色对象的边界,灰色对象就是这个波面。 当垃圾回收开始时,只有白色对象。...这个过程可以视为以灰色对象为波面,将黑色对象和白色对象分离,使波面不断向前推进,直到所有可达的灰色对象都变为黑色对象为止的过程。如下图所示: ?...) { shade(*slot) *slot = ptr } 为了防止丢失从灰色对象到白色对象的路径,应该假设 *slot 可能会变为黑色,为了确保 ptr 不会在被赋值到 *slot...前变为白色, shade(*slot) 会先将 *slot 标记为灰色,进而该写操作总是创造了一条灰色到灰色或者灰色到白色对象的路径,进而避免了条件 2。...sync.Pool 是内存复用的一个最为显著的例子,从语言层面上还有很多类似的例子,例如在例 1 中, concat 函数可以预先分配一定长度的缓存,而后再通过 append 的方式将字符串存储到缓存中
领取专属 10元无门槛券
手把手带您无忧上云