go语言有gc

gc采用标记清除

并行gc

gc不分代

无vm

谈go语言gc之前,先了解一下基础概念

一个标准进程的内存模型code area(方法区)

static area 静态变量

heap (堆)

stack (栈)

golang程序,是一个进程;

一个进程对应着多个OS线程,又根据MPG模型,对应着很多个协程;

对所有的goroutinue来说,heap可以看作是共享的区域;

但是每个goroutinue,都有只属于自己的stack;

一般程序的内存管理

stack会随着线程执行code area的stack frame,自动pop、push、remove;

stack里的变量、调用完毕,就随着出栈,自动销毁;

但是heap不会,heap内的对象,通常是用stack内或者其它heap对象内的指针变量,对heap内的对象进行操作;

这个也叫做对象引用;

垃圾回收,garbage collect,回收的就是heap的空间;

Gc方式标记/清除标记:就是遍历gcRoot,找到存活的对象,并给他们打上标记。

清除:在标记之后执行,将之前未标记上的对象给清除,然后将之前标记上的对象的标记置空。

通俗的讲就是程序发现内存不够的时候,gc线程就会触发将当前应用程序暂停,然后进行遍历打上标记,然后清除未打上标记的对象再清除之前的标记,最后程序恢复运行。

标记/清除算法的优势是占用空间比较小,但是效率比较低,而且会导致之前的排列杂乱无章,而为了应付这一点,JVM就不得不维持一个内存的空闲列表,这又是一种开销。而且在分配数组对象的时候,寻找连续的内存空间会不太好找。

复制复制算法就是将内存一分为二,分为空闲区和活动区,当活动区的内存达到上限时,则将活动区的所有存活对象按照原来的顺序呢复制到空闲区,然后把活动区和内存去相互置换,同时也把之前的活动区的辣鸡对象清除。

复制算法的优势在于效率很高,但是效率高的代价就是占用两倍的内存。而且当对象存活率非常高的时候,这种开销是不可忽视的。

标记/整理标记:就是遍历gcRoot,找到存活的对象,并给他们打上标记。

整理:移动所有之前标记的存活对象,且按照内存地址值排列,然后将具有内存地址值之后的所有内存清空。

此算法标记过程同上(标记/清除算法)一样,而整理过程和复制算法一样,但是没有内存划分这么一说,少了不必要的内存开销。记/整理算法唯一的缺点就是效率也不高,不仅要标记所有存活对象,还要整理所有存活对象的引用地址。从效率上来说,标记/整理算法要低于复制算法

golang的gc

golang的gc介绍,全都在上面这个链接中;

要点写屏障

gray black white三色标记黑色: 对象在这次GC中已标记,且这个对象包含的子对象也已标记

灰色: 对象在这次GC中已标记, 但这个对象包含的子对象未标记

白色: 对象在这次GC中未标记gc-root可达性分析

并行的标记/扫描

STW 停止世界(暂停用户协程)/启动用户协程

流程图(翻译自以上链接)golang gc 流程图

核心概念gcphase Gc阶段状态,runtime的内部变量

P mpg模型中的Processer

mcache golang的一个非常重要的管理机制;每个P下面都有一个mcache;

root marking jobs :其实就是gc root可达性分析标记

之前的一个版本的golang mgc.go文件注释里,还有下面的描述,现在这些描述都不见了除了每个P下的标记worker,还有一个全局的标记worker

每个worker内部有一个待染色的(对象指针queue)

golang的栈内存管理

golang由于协程的数量可以无限多,需要的栈内存也很多,所以,设计了stack cache pool的机制;

栈内存用来存储函数内变量;在golang函数、协程退出后,其占用的栈内存也会一同被释放。

栈内存管理的核心思想和堆内存很像;在分配时,首先查找线程内stackcache是否有足够的空间,如果有足够的空间,则进行分配,避免了线程间竞争,提高了效率;若线程内stackcache内存不足,则会向全局stackpool中申请一批stack,按照规格进行切分后,放入到线程的stackcache中,然后再次进行分配

(另外,人在武汉,求个北京深圳大厂的工作,wx:timeloveboy)

发布评论
IT源码网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

webkit java项目_js与java互调(webkit开发)讲解
你是第一个吃螃蟹的人
发表评论

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