go gc回收
本文于 1494 天之前发表,文中内容可能已经过时。
go语言的垃圾回收机制,你说一下吧
go语言采用的是三色标记作为它的垃圾回收机制。采用的是并发标记和混合写屏障来完成的。
说一下三色标记吧
三色标记分为三个集合对象,黑白灰。扫描对象,默认所有的对象都是白色的。
从根集开始,依次找到可达对象,放到灰色集合中,
然后再次遍历灰色集合,把它的可达对象放到灰色集合中,而扫描对象本身放到黑色集合中
然后重复此步骤,将所有的灰色集合,都扫描到黑色集合中。最终灰色集合为空。
剩余的白色集合对象,就是不可达对象,需要垃圾回收机制进行清楚地。
采用写屏障保障顺利执行,写屏障的好处是有些指针操作的时候,可能一面进行指针赋值的过程,一面进行垃圾回收机制,
go的垃圾回收是并发进行的。所以可能导致指针的指向出现问题,所以在指针进行赋值之前,它开启了一个写屏障。
当指针赋值之后,再将写屏障关闭。
如果你的指针赋值过程中,是在垃圾回收机制运行过程中的,不会被gc所扫描。关闭写屏障,那么下一次扫描的时候,才会
进行三色判断。
gc分为三步,
第一步是启动,通过malloc 创建内存空间,同时创建内存空间的时候,会有一个标记。
标记可以分为两块,一个是扫描、一个是标记、还有清理
清理时把所有的白色的不可达对象进行回收,所谓回收就是将内存归还给mcache,以方便下一次使用
这个算法可以实现 “on-the-fly”,也就是在程序执行的同时进行收集,并不需要暂停整个程序。
但是也会有一个缺陷,可能程序中的垃圾产生的速度会大于垃圾收集的速度,这样会导致程序中的垃圾越来越多无法被收集掉。
使用这种算法的是 Go 1.5、Go 1.6。
go 除了标准的三色收集以外,还有一个辅助回收功能,防止垃圾产生过快手机不过来的情况。这部分代码在 runtime.gcAssistAlloc 中。
但是 golang 并没有分代收集,所以对于巨量的小对象还是很苦手的,会导致整个 mark 过程十分长,在某些极端情况下,甚至会导致 GC 线程占据 50% 以上的 CPU。
因此,当程序由于高并发等原因造成大量小对象的gc问题时,最好可以使用 sync.Pool 等对象池技术,避免大量小对象加大 GC 压力。
常见垃圾回收机制php使用的
- 引用计数法
原理是在每个对象内部维护一个整数值,叫做这个对象的引用计数,当对象被引用时引用计数加一,当对象不被引用时引用计数减一。当引用计数为 0 时,自动销毁对象。
目前引用计数法主要用在 c++ 标准库的 std::shared_ptr 、微软的 COM 、Objective-C 和 PHP 中。
但是引用计数法有个缺陷就是不能解决循环引用的问题。循环引用是指对象 A 和对象 B 互相持有对方的引用。这样两个对象的引用计数都不是 0 ,因此永远不能被收集。
另外的缺陷是,每次对象的赋值都要将引用计数加一,增加了消耗。
写屏障:该屏障之前的写操作和之后的写操作相比,先被系统其它组件感知。
通俗的讲:就是在gc跑的过程中,可以监控对象的内存修改,并对对象进行重新标记。(实际上也是超短暂的stw,然后对对象进行标记)
在上述情况中,新生成的对象,一律都标位灰色!
写屏障监视对象的内存修改,重新标色或放回队列