前言
只有光头才能变强
在读《Redis设计与实现》关于哈希表扩容的时候,发现这么一段话:
执行BGSAVE命令或者BGREWRITEAOF命令的过程中,Redis需要创建当前服务器进程的子进程,而大多数操作系统都采用写时复制(copy-on-write)来优化子进程的使用效率,所以在子进程存在期间,服务器会提高负载因子的阈值,从而避免在子进程存在期间进行哈希表扩展操作,避免不必要的内存写入操作,最大限度地节约内存。
触及到知识的盲区了,于是就去搜了一下copy-on-write写时复制这个技术究竟是怎么样的。发现涉及的东西蛮多的,也挺难读懂的。于是就写下这篇笔记来记录一下我学习copy-on-write的过程。
本文力求简单讲清copy-on-write这个知识点,希望大家看完能有所收获。
一、Linux下的copy-on-write
在说明Linux下的copy-on-write机制前,我们首先要知道两个函数:fork()
和exec()
。需要注意的是exec()
并不是一个特定的函数, 它是一组函数的统称, 它包括了execl()
、execlp()
、execv()
、execle()
、execve()
、execvp()
。
1.1简单来用用fork
首先我们来看一下fork()
函数是什么鬼:
fork is an operation whereby a process creates a copy of itself.
fork是类Unix操作系统上创建进程的主要方法。fork用于创建子进程(等同于当前进程的副本)。
新的进程要通过老的进程复制自身得到,这就是fork!
如果接触过Linux,我们会知道Linux下init进程是所有进程的爹(相当于Java中的Object对象)
Linux的进程都通过init进程或init的子进程fork(vfork)出来的。
下面以例子说明一下fork吧:
#include <unistd.h> #include <stdio.h> int main () { pid_t fpid; //fpid表示fork函数返回的值 int count=0; // 调用fork,创建出子进程 fpid=fork(); // 所以下面的代码有两个进程执行! if (fpid < 0) printf("创建进程失败!/n"); else if (fpid == 0) { printf("我是子进程,由父进程fork出来/n"); count++; } else { printf("我是父进程/n"); count++; } printf("统计结果是: %d/n",count); return 0; }
得到的结果输出为:
我是子进程,由父进程fork出来 统计结果是: 1 我是父进程 统计结果是: 1
解释一下:
fork作为一个函数被调用。这个函数会有两次返回,将子进程的PID返回给父进程,0返回给子进程。(如果小于0,则说明创建子进程失败)。
再次说明:当前进程调用
fork()
,会创建一个跟当前进程完全相同的子进程(除了pid),所以子进程同样是会执行fork()
之后的代码。
所以说:
父进程在执行if代码块的时候,
fpid变量
的值是子进程的pid子进程在执行if代码块的时候,
fpid变量
的值是0
1.2再来看看exec()函数
从上面我们已经知道了fork会创建一个子进程。子进程的是父进程的副本。
exec函数的作用就是:装载一个新的程序(可执行映像)覆盖当前进程内存空间中的映像,从而执行不同的任务。
exec系列函数在执行时会直接替换掉当前进程的地址空间。
我去画张图来理解一下:
exec函数的作用
作者:Java3y
链接:https://www.jianshu.com/p/2548587b58b1
共同学习,写下你的评论
评论加载中...
作者其他优质文章