1.4G虚拟地址空间的内存分配
空指针有指向,小整数值 《C专家编程》
系统运行时,从0x0804800开始装载,代码段开始 malloc 堆
2. fork()进程复制的流程
当fork()函数被调用时,内核就会为新进程创建各种数据结构,并分配给该进程一个唯一的pid。子进程和父进程用的是相同的内存空间,也就是说子进程的代码段,数据段,堆栈都是指向父进程的物理空间,两者的虚拟空间不同,但是对应的相同的物理空间。当父子进程中有更改相应段的操作发生时,系统会给子进程分配物理空间。这就是写时拷贝。
fork()函数调用一次,返回两次,三种返回值
1. 父进程中的返回值是子进程的pid
2. 子进程中fork成功的话返回值为0,失败的话返回值是-1
注意:子进程和父进程访问变量的值却不改变 变量的值,相当于读取了一下,这个时候不会给子进程分配新的资源,而是接着共享父进程的资源。但当系统发现子进程或者父进程要该表某一变量的值的时候,系统就会给子进程分配心的内存空间,然后子进程将父进程中fork之前的变量拷贝一份,此时此刻,子进程和父进程的内存空间已经不同了。写时拷贝是以“页”为单位复制的。
系统最多可以运行多少进程?为什么?
每一个系统能够运行进程数量不同,可以通过ulimit -u来查看我们自己的系统中的进程上线。当然这是可以改变的。通过ulimit -u 数值来改变。我们用pid_t来表示进程的pid,能表示的进程范围一定不会超过pid_t类型的大小,通用命令:cat/proc/sys/kernel/pid_max 来查看最大进程数。查到的数值是32768,这只是一个理论值,实际上由于内存等系统资源的的限制,根本不会同时有这么多的进程存在,并且进程pid是从300往上申请的,因为系统的程序需要占用许多pid。
不考虑资源的使用情况,pid为一个整形,整形的上限就是进程的上限,32678
pid从300开始, 不确定是系统进程还是用户进程 系统进程一般比较少
关于fork的笔试题
int main()
{
int i = 0;
for(;i < 2;i++)
{
fork();
printf("A\n");
}
}
打印6个A
int main()
{
int i = 0;
for(;i < 2;i++)
{
fork();
printf("A");
}
}
打印8个A
int main()
{
fork() || fork();
printf("A\n");
}
打印3个A,第一个fork执行之后,父进程打印一个A,但是子进程中返回值是0,第一个fork假,执行第二个fork,子进程再fork出一个子进程,所以两个子进程打印两个A。所以一共3个A
int main()
{
printf("A");
write(1,"B",1);
fork();
}
打印BAA,printf("A"),没有\n,所以这个A在main函数的缓冲区中,write系统调用,直接将B打印在屏幕上,
fork之后,复制了一份缓冲区中的A,现在缓冲区中两个A,系统结束之后,将缓冲区中的两个A全部打印咱屏幕上
3. main函数的三个参数
int main(int argc,char* argv[],char* envp)
argc :参数个数
argv:参数内容
envp:环境变量即envp的值
4. 信号
信号是系统预先编译好的某些特定的事件,信号可以被产生,可以被接收,产生和接收的主体是进程。
信号的三种相应方式
忽略:SIG_ING
默认:SIG_DFL
自定义:自己写的信号处理函数
改变信号量的处理方式是signa()函数。
kill()函数可以向指定的进程发送指定的信号
例如:int kill(pid_t pid,int sig)
pid > 0 指定将信号发送给那个进程
pid == 0 信号被发送到和当前进程在同一个进程组的进程
pid == -1 将信号发送给系统上有权限发送的所有的进程
SIGCHLD是子进程结束后给父进程发的退出信号
SIGINT 2 等价于ctrl +c
15 默认kill
9 kill -9 杀死进程,但不改变相应方式