对Python,Golang和C++三种语言GC机制的简单调查

调查背景

在公司一项任务是需要调用Python的SDK爬取相关的数据信息,数据的量在10亿这个量级,故不能够一下子得到结果。
这个程序运行十来天的可能性比较大,但是问题来了,程序跑过一阵子(1小时)之后爬取效率明显降低。
重启之后效率恢复,这就让人有点不爽了,本来数据量就多,用初速度爬取也需要十来天,这样一减速得爬到什么时候呢?
通过使用top工具,观察到爬虫脚本在运行过程中占用的内存从800MB上升到了1.4GB,速度也随内存占用量的上升而减慢。(图片来自MacOS的top,与程序的运行环境中的top不太一样)

我猜可能是内存泄漏了,各种查资料之后用python的gcobjgraph进行程序内存使用情况分析。
虽然针对于爬虫程序的分析无果,但是对GC机制有了一点兴趣,于是稍微了解了一下。

下文的 GC 既指 Garbage Collection, 也指 Garbage Collector。

接触Python一年多,Golang九个月,C++是大一时OOP课上教授的语言。其实都只是了解了皮毛,仅仅停留在“会用”这个层面。

三种语言的GC机制

Python

1. 引用计数
引用计数是一个很简单的实现方式,顾名思义:

  • 当一个对象被引用时,该对象的引用次数+1;
  • 当引用这个对象的另一个对象被GC回收时,该对象的引用次数-1;
    当GC监测到某对象的引用次数为0时则将该对象回收。

但是这个方案无法解决循环引用

2. 分代回收
根据对象的存活周期不同将内存划分为新生代和老年代,存活周期短的为新生代,存活时间长的为老年代。
这样就可以根据每块内存的特点采用适当的收集算法。
在新生代对象中进行高频回收,在这次回收中没有被清理的对象移动到老年代对象中,老年代对象执行低频回收。


上面是分代回收的定义,但是python没有简单的把对象分为两个代际,而是分为了三代。每一代的对象达到了一定的数量(Threshold)之后GC会执行相应代际的对象回收,这个阈值是可以通过gc包进行设置的(gc.set_threshold),我调用gc.get_threshold()得到的结果是(700, 10, 10)
不像引用计数,分代回收是可以进行控制的,甚至是关闭。如果觉得GC太频繁造成了性能瓶颈,那么可以提高阈值,降低GC频率。

Golang

1. STW
Golang的早期版本被无数人所诟病的问题之一就是它的GC,它用的是标记清除方法,也叫Stop The World(STW)
该方法从根变量开始迭代,遍历所有被引用的对象,能够访问到的都标记上“被引用”;之后对没有标记过的对象进行清理,即回收不可达的对象。但是每次执行该算法都会让正常执行的
内存负荷型程序
出现明显的卡顿,这也是为什么该方法又被叫做STW的原因。

2. 三色标记法
该方法是对标记清除算法的改进,原理如下:

  1. 起初所有对象都是白色的;
  2. 从根对象出发扫描所有可达对象,标记为灰色,放入待处理队列;
  3. 从队列取出灰色对象,将其引用对象标记为灰色放入队列,自身标记为黑色;
  4. 重复步骤3,直到灰色对象的队列为空。这时仍为白色的对象被当作垃圾回收。

下面是演示图:

C++

In early programming languages, developers were responsible for all memory management in their programs. This meant before creating a list or an object, you first needed to allocate the memory for your variable. After you were done with your variable, you then needed to deallocate it to “free” that memory for other users.[2]

C++就是early programming language,它较Python和Golang而言更偏底层和接近系统,将内存管理的工作交给程序员来完成。简而言之,就是没有GC(当然后来的C++11、14的新特性在此不提及)我之前写的某程序就因为想要释放整个数组的空间但是只写了delete xxx而不是delete[] xxx,仅释放了数组首位元素的空间,导致了剩余所有元素内存资源的浪费。
为了减轻程序员手动管理内存的痛苦,C++11推出的智能指针算是一个宝贝。

参考资料

  1. GO GC 垃圾回收机制
  2. Python Garbage Collection: What It Is and How It Works
  3. 如何理解智能指针? - 知乎

对Python,Golang和C++三种语言GC机制的简单调查

https://powerfooi.github.io/2019/06/12/GarbageCollectionSurvey/

作者

PowerfooI

发布于

2019-06-12

更新于

2024-08-04

许可协议

评论