Python垃圾回收和Linux Fork
前言
在口袋助理看到了其他部门的同事针对Python2内存占用做的一点优化工作,自己比较感兴趣,遂记录下。
Linux fork简介
fork是Linux提供的创建子进程的系统调用。为了优化创建进程速度,Linux内核使用了Copy-on-Write的方式去创建进程,所谓Copy-on-Write是指执行fork之后,
内核并不立即给子进程分配物理内存空间,而是让子进程的虚内存映射到父进程的物理内存。仅仅当子进程向地址空间中执行写入操作时,才给它分配一段物理内存。
通过这种方式既优化了进程创建的时间,又减少了子进程的内存占用。
Copy-On-Write策略增加Python多进程内存占用的原因
Python GC采用引用技术的方式去管理对每个对象的引用,每一个被GC跟踪的对象会由一个PyGC_Head的结构体去表示。如下所示,其中gc_refs就是每个对象的引用计数值,
当我们在子进程中读取父进程创建的对象的时候,就会导致子进程的虚地址空间中的gc_refs加1,从而触发了内核的缺页中断,这是内核就会给子进程创建新的物理内存。
仅仅是简单的读取操作就会导致新的内存空间产生。
/* GC information is stored BEFORE the object structure. */
typedef union _gc_head
{
struct {
union _gc_head *gc_next;
union _gc_head *gc_prev;
Py_ssize_t gc_refs;
} gc;
long double dummy; /* force worst-case alignment */
} PyGC_Head;
解决办法
python3的解决方法
针对这个问题,Python3.7增加了三组API(有instagram团体提交的)[1]。

freeze用于将GC追踪的所有对象都移动到永生代(permanent generation),之后垃圾回收会忽略这些被设置为永生代的对象。
实际使用中,我们可以在父进程中执行freeze函数,然后子进程中使用和父进程共享的对象,这样对象的引用技术就不会增加,从而避免了COW的发生。
python2的解决方法
(1) 针对Python2,我们可以简单的把Python3的相关函数移植过来
(2) 使用multiprocessing.Array去共享数据。Array会从共享内存中取一段取存储数据,并不会增加引用技术值,从而触发COW。
实现方面,Array使用Posix共享内存 + mmap去实现。[3]
#!/usr/bin/env python
# coding=utf-8
from multiprocessing import Array
import os
import sys
def foo():
shared_cache = Array('i', range(0, 100), lock=False)
pid = os.fork()
if pid > 0:
print("parent:", sys.getrefcount(shared_cache))
elif pid == 0:
print("child:", sys.getrefcount(shared_cache))
foo()
参考
1.https://instagram-engineering.com/copy-on-write-friendly-python-garbage-collection-ad6ed5233ddf
2.https://llvllatrix.wordpress.com/2016/02/19/python-vs-copy-on-write/
3.https://github.com/python/cpython/blob/main/Lib/multiprocessing/shared_memory.py
Python垃圾回收和Linux Fork的更多相关文章
- Python垃圾回收机制--完美讲解!
转自: http://www.jianshu.com/p/1e375fb40506 先来个概述,第二部分的画述才是厉害的. Garbage collection(GC) 现在的高级语言如java,c# ...
- python垃圾回收机制与小整数池
python垃圾回收机制 当引用计数为0时,python会删除这个值. 引用计数 x = 10 y = x del x print(y) 10 引用计数+1,引用计数+1,引用计数-1,此时引用计数为 ...
- python垃圾回收机制:引用计数 VS js垃圾回收机制:标记清除
js垃圾回收机制:标记清除 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. JS中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...
- python 垃圾回收
# 垃圾回收 # 小整数对象池 # a = 100# python对小整数的定义是[-5,257],这些证书对象是提前创建好的,不会被垃圾回收,再一个python的程序中,所有位于这个范围内的正式使用 ...
- python垃圾回收
python垃圾回收 python垃圾回收主要使用引用计数来跟踪和回收垃圾.在引用计数的基础上,通过“标记—清除”解决容器对象可能产生的循环引用问题,通过“分代回收”以空间换时间的方法提高垃圾回收效率 ...
- 《垃圾回收的算法与实现》——Python垃圾回收
Python垃圾回收 python采用引用计数法进行垃圾回收 Python内存分配 python在分配内存空间时,在malloc之上堆放了3个独立的分层. python内存分配时主要由arena.po ...
- python垃圾回收机制(Garbage collection)
由于面试中遇到了垃圾回收的问题,转载学习和总结这个问题. 在C/C++中采用用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但也为大量内存泄露.悬空指针等bug埋下隐患. 因此在现 ...
- python 垃圾回收详解
原文:https://zhuanlan.zhihu.com/p/31150408 总纲 策略和垃圾回收系统工作内容 引用计数详解 标记-清除+分代收集 循环引用 编程应用-常见方法 ex 过程详解 使 ...
- python垃圾回收算法
标准python垃圾回收器由两部分组成,即引用计数回收器和分代垃圾回收器(即python包中的gc module).其中,引用计数模块不能被禁用,而GC模块可以被禁用. 引用计数算法 python中每 ...
随机推荐
- Table.Distinct取唯/众数….Distinct/Mode/判断…IsDistinct(Power Query 之 M 语言)
数据源: "姓名""基数""个人比例""个人缴纳""公司比例""公司缴纳"&qu ...
- CF1490D Permutation Transformation 题解
Content 给定一个排列 \(a\),按照以下方法构造一棵树: 选择当前排列中的最大数作为根的编号. 最大数左边的所有数按照上述方法建左子树,若没有数则该节点没有左儿子. 最大数右边的所有数按照上 ...
- CentOS系统 python3+python2 & Ipython安装
https://www.cnblogs.com/albertrui/p/8093384.html 一.安装依赖环境 输入命令: yum -y install zlib-devel bzip2-deve ...
- AcWing422. 校门外的树
题目: 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米. 我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,--,L,都种 ...
- 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)[本文] 再谈多线程模型之生 ...
- 【LeetCode】429. N-ary Tree Level Order Traversal 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:BFS 方法二:DFS 参考资料 日期 题目 ...
- Bristol大学密码学博士生的五十二个知识点
Bristol大学密码学博士生的五十二个知识点 这个系列,是Bristol大学的密码安全工作组为密码学和信息安全相关的博士准备了52个基本知识点. 原地址:http://bristolcrypto.b ...
- 源码分析 SpringCloud 2020.0.4 版本 EurekaClient 的注册过程
1. 概述 老话说的好:要善于思考,有创新意识. 言归正传,之前聊了 Springboot 的启动过程,今天来聊聊 Eureka Client 的注册过程. 2. Eureka Client 的注册过 ...
- CS5211设计EDP转LVDSA转接屏|替代LT7211|DP转LVDS屏驱动 转接板
LT7211是一种用于虚拟现实/显示应用的高性能C/DP1.2至LVDS芯片. 对于DP1.2输入,LT7211可以配置为1.2.4车道,还支持车道交换功能.自适应均衡使其适用于长电缆应用,最大带宽可 ...
- 生成器执行函数co 源码解读
本文所选内容均来自[co模块源码] /** * slice() reference. */ var slice = Array.prototype.slice; module.exports = co ...