Linux系统编程之进程(关键概念)

一、什么是程序,什么是进程,有什么区别?
二、如何查看系统中有哪些进程?
三、什么是进程标识符?
四、什么叫父进程,什么叫子进程?
五、C程序的存储空间是如何分配?

一、什么是程序,什么是进程,有什么区别?

  • 程序是静态的概念,gcc xxx.c –o pro磁盘中生成pro文件,叫做程序
  • 进程是程序的一次运行活动,通俗点意思是程序跑起来了,系统中就多了一个进程

二、如何查看系统中有哪些进程?

在Ubuntu下

  • a.使用ps指令查看
    实际工作中,配合grep来查找程序中是否存在某一个进程
  • b.使用top指令查看,类似windows任务管理器

1. ps指令

ps
ps -aux

请添加图片描述

实际中通过管道(|)和 grep 来过滤进程的数据
ps -aux|grep init

请添加图片描述

2. top指令

top

CPU占用率
MEM硬件使用率

请添加图片描述

1. 上半部分显示了整体系统负载情况
top 第一行:

从左到右依次为当前系统时间,系统运行的时间,系统在之前1min、5min和15min内cpu的平均负载值
20:43:24 ====> 当前系统时间是 20:43:24
up 1 days, 1 :29 ====> 系统运行时间为1天1小时29分钟(在此期间没有重启过)
1 user ===> 当前有1个用户登录系统
load average ===> 系统在之前1min、5min、15min之内CPU的平均负载值

任务Tasks一行:

该行给出进程整体的统计信息,包括统计周期内进程总数、运行状态进程数、休眠状态进程数、停止状态进程数和僵尸状态进程数

  • 统计周期内进程总数 ====> 298
  • 运行状态进程数 ====> 1
  • 休眠状态进程数 ====> 297
  • 停止状态进程数 ====> 0
  • 僵尸状态进程数 ====> 0
    这里顺带普及一下杀掉僵尸进程 可以参考我的这篇文章:
%Cpu(s)一行:

cpu整体统计信息,包括用户态下进程、系统态下进程占用cpu时间比,nice值大于0的进程在用户态下占用cpu时间比,cpu处于idle状态、wait状态的时间比,以及处理硬中断、软中断的时间比

  • 0.0%us, 0.2%sy, 这个为用户空间和内核空间所占cpu百分比
    -用户态下进程占用cpu时间比 ====> 0.0%
    -内核态下进程占用cpu时间比 ====> 0.2%
  • 0.0 ni 用户进程空间内改变过优先级的进程占用CPU百分比
  • 99.8 id 空闲CPU百分比
  • 0.0 wa 等待输入输出的CPU时间百分比
  • 0.0 hi 硬中断(Hardware IRQ)占用CPU的百分比
  • 0.0 si 软中断(Software Interrupts)占用CPU的百分比
Mem一行:

该行提供了内存统计信息,包括物理内存总量、已用内存、空闲内存以及用作缓冲区的内存量
MiB Mem: 3871.6 total, 1145.1 free, 1225.7 used, 1500.8 buffer/cache

  • 3871.6 total 物理内存总量
  • 1145.1 free 空间内存总量
  • 1225.7 used 已用内存总量
  • 1500.8 buffer/cache 用作缓冲区的内存量
Swap一行:

虚存统计信息,包括交换空间总量、已用交换区大小、空闲交换区大小以及用作缓存的交换空间大小
MiB Swap: 3898.0 total, 3898.0 free, 0.0 used, 2350.4 avail Mem
这行为交换分区使用情况,和上面内存的解释基本一致

  • 3898.0 total, 交换分区物理内存总量
  • 3898.0 free, 交换分区空间内存总量
  • 0.0 used, 交换分区已用内存总量
  • 2350.4 avail Mem 交换分区用作缓冲区的内存量
2. 下半部分表头
PID   USER  PR NI   VIRT  RES  SHR   S  %CPU  %MEM   TIME+ COMMAND
  • PID 进程号
  • USER 用户名
  • PR 优先级(priority )
  • NI nice值。负值表示高优先级,正值表示低优先级m
  • VIRT 进程使用的虚拟内存总量
  • RES 进程使用的、未被换出的物理内存大小,单位kb
  • SHR 共享内存大小,单位kb
  • S 进程状态。
  • D=不可中断的睡眠状态
  • R=运行
  • S=睡眠
  • T=跟踪/停止
  • Z=僵尸进程
  • %CPU CPU使用率
  • %MEM 进程使用的物理内存百分比
  • TIME+ 进程使用的CPU时间总计,单位1/100秒
  • COMMAND 执行的命令
top常用总结
  • top 默认每隔5秒显式所有进程的资源占用情况
  • top -d 10 每隔10秒显式所有进程的资源占用情况
  • top -c 每隔5秒显式进程的资源占用情况,并显示进程的命令行参数(默认只有进程名)
  • top -p 2088 -p 3088 每隔5秒显示pid是2088和pid是3088的两个进程的资源占用情况
  • top -d 2 -c -p 3008 每隔2秒显示pid是3008的进程的资源使用情况,并显式该进程启动的命令行参数

三、什么是进程标识符?

每个进程都有一个`非负整数`表示的唯一ID,叫做`pid`,类似身份证

Pid=0:  称为交换进程(swapper)
作用—进程调度
Pid=1:init进程
作用—系统初始化

>进程调度算法也称 CPU 调度算法,毕竟进程是由 CPU 调度的。
>首个进程在你启动 Linux 发行版时开始运行,它称为初始化进程 init(初始化(initialization)的缩写)。
它的进程标识符为 1(即 pid=1)。基于 Unix 的系统中的所有进程和应用程序都是这个初始化进程的后代。

编程调用`getpid函数`获取自身的进程标识符
`getppid`获取父进程的进程标识符

getpid()、getppid()

SYNOPSIS
       #include <sys/types.h>
       #include <unistd.h>

       pid_t getpid(void);
       pid_t getppid(void);
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
	pid_t pid;

	//pid_t getpid(void);
	pid = getpid();
	//pid_t getppid(void);
	
	printf("my pid is %d\n",pid);

	while(1);

	return 0;
}       

请添加图片描述

四、什么叫父进程,什么叫子进程?

进程A创建了进程B
那么A叫做父进程,B叫做子进程,父子进程是相对的概念,理解为人类中的父子关系

五、C程序的存储空间是如何分配?

《UNIX环境高级编程》PDF 文献 提取码: PRO1
CSDN博文

由于历史原因,C程序一直由下列几部分组成:
  • 正文段。

这是由CPU执行的机器指令部分。通常,正文段是可共享的,所以即使是经常执行的程序(如文本编辑程序、C编译程序、shell等)在存储器中也只需有一个副本,另外,正文段常常是只读的,以防止程序由于意外事故而修改其自身的指令。

  • 初始化数据段。

通常将此段称为数据段,它包含了程序中需赋初值的变量。例如, C程序中任何函数之外的说明:
int maxcount = 99;
使此变量以初值存放在初始化数据段中。

  • 非初始化数据段。

通常将此段称为 bss段,这一名称来源于早期汇编程序的一个操作符,意思是“block started by symbol(由符号开始的块)”,在程序开始执行之前,内核将此段初始化为0。函数外的说明:
long sum[1000] ;
使此变量存放在非初始化数据段中。

  • 栈。

自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次函数调用时,其返回地址、以及调用者的环境信息(例如某些机器寄存器)都存放在栈中。然后,新被调用的函数在栈上为其自动和临时变量分配存储空间。通过以这种方式使用栈, C函数可以递归调用。

  • 堆。

通常在堆中进行动态存储分配。由于历史上形成的惯例,堆位于非初始化数据段顶和栈底之间。
请添加图片描述

图7 - 3显示了这些段的一种典型安排方式。

这是程序的逻辑布局—虽然并不要求一个具体实现一定以这种方式安排其存储空间。尽管如此,这给出了一个我们便于作有关说明的一种典型安排。
对于VAX上的4.3 + BSD,正文段从 0位置开始,栈顶则在0x7fffffff之下开始。在VAX机器上,堆顶和栈底之间未用的虚地址空间很大。
从图7 - 3还可注意到末初始化数据段的内容并不存放在磁盘程序文件中。需要存放在磁盘程序文件中的段只有正文段和初始化数据段。
size (1)命令报告正文段、数据段和 bss段的长度(单位:字节)。例如:
$ size /bin/cc /bin/sh

textdatabssdechexfilename
81920163846649896818298/bin/cc
901121638401064961a000/bin/sh

第4和第5列是分别以十进制和十六进制表示的总长度。

#include <stdlib.h>

int a = 0;    //a在全局已初始化数据区 
char *p1;    //p1在BSS区(未初始化全局变量)

void main() 
{
    int b; //b在栈区
    int c; //C为全局(静态)数据,存在于已初始化数据区
    char s[] = "abc"; //s为数组变量,存储在栈区,
    char *p2,*p3;  //p2、p3在栈区

    p2 = (char *)malloc(10);//分配得来的10个字节的区域在堆区
    p3 = (char *)malloc(20);//分配得来的20个字节的区域在堆区

    free(p2);
    free(p3);
}

请添加图片描述

代码段(text / code):流程控制 、算法

存放代码的地方。只能访问,不能修改,代码段就是程序中的可执行部分,直观理解代码段就是函数堆叠组成的。

数据段(data):初始化的数据、变量

全局变量静态局部变量存放的地方。也被称为数据区、静态数据区、静态区:数据段就是程序中的数据,直观理解就是C语言程序中的全局变量。注意是全局变量或静态局部变量,局部变量不算。

未初始化数据区(bss):函数外未初始化的数据、变量

bss段的特点就是被初始化为0,bss段本质上也是属于数据段。

那么问题来了,为什么要区分data段和bss段呢?

以下面代码为例,a.c和b.c的差异只是有没有给arr数组赋值。
请添加图片描述
​可以看到a.out的bss段大,b.out的data段大。但是b.out的文件大小明显比a.out的大很多。
请添加图片描述
​那么就可以简单理解为,data段会增大可执行文件的大小,而bss段不会。

c语音程序的段

一、前言

C语言程序经过编译连接后形成编译、连接后形成的二进制映像文件由栈,堆,数据段(由三部分部分组成:只读数据段,已经初始化读写数据段,未初始化数据段即BBS)和代码段组成。

堆栈(英语:stack)

是计算机科学中一种特殊的串列形式的抽象数据类型,其特殊之处在于只能允许在链表或数组的一端(称为堆栈顶端指针,英语:top)进行加入数据(英语:push)和输出数据(英语:pop)的运算。另外堆栈也可以用一维数组或链表的形式来完成。堆栈的另外一个相对的操作方式称为队列。需要记住的是,堆:顺序随意,栈:后进先出(Last-In/First-Out)。
这里的pop和push到都是什么意思?其实这是堆栈数据结构使用两种基本操作:
推入(压栈,push)和弹出(弹栈,pop):

  • 推入:将数据放入堆栈的顶端(数组形式或串列形式),堆栈顶端top指针加一。
  • 弹出:将顶端数据数据输出(回传),堆栈顶端数据减一。

如要了解堆栈,应将之拆开分析。

堆(heap):calloc、malloc等相关的函数去申请空间

是计算机科学中的一种特别的树状数据结构。通常是一个可以被看做一棵树的数组对象。若是满足以下特性,即可称为堆:“给定堆中任意节点 P 和 C,若 P 是 C 的父节点,那么 P 的值会小于等于(或大于等于) C 的值”。若父节点的值恒小于等于子节点的值,此堆称为最小堆(英语:min heap);反之,若父节点的值恒大于等于子节点的值,此堆称为最大堆(英语:max heap)。在堆中最顶端的那一个节点,称作根节点(英语:root node),根节点本身没有父节点(英语:parent node)。

栈(stack):局部变量、局部的自动变量、函数调用保存返回的地址和函数运行等

栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。栈就是一个桶,后放进去的先拿出来,它下面本来有的东西要等它出来之后才能出来(先进后出

栈(Stack)是操作系统在建立某个进程时或者线程在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有FIFO的特性,在编译的时候可以指定需要的Stack的大小。

其实堆栈本身就是栈,只是换了个抽象的名字。其特性是: 最后一个放入堆栈中的物体总是被最先拿出来,这个特性通常称为后进先出(LIFO)队列。堆栈中定义了一些操作。 两个最重要就是上述提到的PUSH和POP。PUSH操作在堆栈的顶部加入一个元素,POP操作相反,在堆栈顶部移去一个元素,并将堆栈的大小减一。

二者区别

堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。它由程序员分配和回收。

栈就是一个桶,后放进去的先拿出来,它下面本来有的东西要等它出来之后才能出来。(后进先出)由系统自动分配和回收。

堆栈缓存方式

栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放。

堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。

栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

作为“堆”的数据空间,必须是灵活的,因为成千上万的程序员在写什么程序是未知的。但可知道的一点,就是他们是跑在确定的某个OS里面的。因此,也不过就是给系统管理的数据空间起了个名字,叫栈;给程序员使用的空间,起了个名,叫堆。

请添加图片描述
1.栈区(stack):又叫堆栈,先进先出,由编译器自动分配释放,存放函数的参数值,局部变量等值。其操作方式类似于数据结构中的栈。

2.堆区(heap):一般由程序员分配释放,若程序员不释放,则可能会引起内存泄漏。注堆和数据结构中的堆栈不一样,其类是与链表。

3.程序代码区:存放函数体的二进制代码。

4.数据段:由三部分组成:
对于裸机开发,为什么需要一个用汇编写的头,因为C语言运行必须要有堆和栈(堆栈)

区别于数据机构当中的堆栈,数据结构当中的堆栈是两种不同的数据结构,栈是后进先出的一种,好像一个往一个盒子里放书一样,最后放的先取出来,堆是一种树型数据结构,存取是随意的。

  1. 只读数据段(RO Data):

只读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,由于这些变量不需要更改,因此只需要放置在只读存储器中即可。一般是const修饰的变量以及程序中使用的文字常量一般会存放在只读数据段中。

  1. 已初始化的读写数据段(RW Data):

已初始化数据是在程序中声明,并且具有初值的变量,这些变量需要占用存储器的空间,在程序执行时它们需要位于可读写的内存区域内,并且有初值,以供程序运行时读写。在程序中一般为已经初始化的全局变量,已经初始化的静态局部变量(static修饰的已经初始化的变量)

  1. 未初始化段(BSS):

未初始化数据是在程序中声明,但是没有初始化的变量,这些变量在程序运行之前不需要占用存储器的空间。与读写数据段类似,它也属于静态数据区。但是该段中数据没有经过初始化。未初始化数据段只有在运行的初始化阶段才会产生,因此它的大小不会影响目标文件的大小。在程序中一般是没有初始化的全局变量和没有初始化的静态局部变量。

二、堆和栈的区别

  1. 申请方式

(1)栈(satck):由系统自动分配。例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间。

(2)堆(heap):需程序员自己申请(调用malloc,realloc,calloc),并指明大小,并由程序员进行释放。容易产生memory leak.

eg:char p;

  p = (char *)malloc(sizeof(char));

但是,p本身是在栈中。

  1. 申请大小的限制

(1)栈:在windows下栈是向底地址扩展的数据结构,是一块连续的内存区域(它的生长方向与内存的生长方向相反)。栈的大小是固定的。如果申请的空间超过栈的剩余空间时,将提示overflow。

(2)堆:堆是高地址扩展的数据结构(它的生长方向与内存的生长方向相同),是不连续的内存区域。这是由于系统使用链表来存储空闲内存地址的,自然是不连续的,而链表的遍历方向是由底地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。

  1. 系统响应:

(1)栈:只要栈的空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

(2)堆:首先应该知道操作系统有一个记录空闲内存地址的链表,但系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的free语句才能正确的释放本内存空间。另外,找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

说明:对于堆来讲,对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,

  1. 申请效率

(1)栈由系统自动分配,速度快。但程序员是无法控制的

(2)堆是由malloc分配的内存,一般速度比较慢,而且容易产生碎片,不过用起来最方便。

  1. 堆和栈中的存储内容

(1)栈:在函数调用时,第一个进栈的主函数中后的下一条语句的地址,然后是函数的各个参数,参数是从右往左入栈的,然后是函数中的局部变量。注:静态变量是不入栈的。

当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续执行。

(2)堆:一般是在堆的头部用一个字节存放堆的大小。

  1. 存取效率

(1)堆:char *s1=”hellow tigerjibo”;是在编译是就确定的

(2)栈:char s1[]=”hellow tigerjibo”;是在运行时赋值的;用数组比用指针速度更快一些,指针在底层汇编中需要用edx寄存器中转一下,而数组在栈上读取。

补充:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

  1. 分配方式:

(1)堆都是动态分配的,没有静态分配的堆。

(2)栈有两种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的。它的动态分配是由编译器进行释放,无需手工实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖喱年糕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值