如:要获取PID为1的进程信息,你需要查看 /proc/1 这个文件夹。
ps a #输出与终端相关进程信息
ps x #输出与终端无关进程信息
ps ax #输出所有进程信息
ps aux #以用户导向的格式输出所有进程信息
ps axuf #将进程以树形结构显示
打印结果:
[root@localhost ~]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.4 60604 7856 ? Ss Feb02 0:04 /usr/lib/systemd/systemd --switched-root --system --deserialize 24
root 2 0.0 0.0 0 0 ? S Feb02 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S Feb02 0:00 [ksoftirqd/0]
root 5 0.0 0.0 0 0 ? S< Feb02 0:00 [kworker/0:0H]
root 7 0.0 0.0 0 0 ? S Feb02 0:00 [migration/0]
root 8 0.0 0.0 0 0 ? S Feb02 0:00 [rcu_bh]
root 9 0.0 0.0 0 0 ? S Feb02 0:00 [rcuob/0]
root 10 0.0 0.0 0 0 ? S Feb02 0:00 [rcuob/1]
USER //用户名称
PID //进程id
%CPU //进程的cpu占用比
%MEM //进程的内存占用比
VSZ //进程的虚拟内存占用比
RSS //常驻内存集大小
TTY //字符终端
STAT //进程状态
START //运行时间
TIME //占用CPU时间
COMMAND //进程名称
ps -e #打印全部进程信息
ps -ef #以全信息格式打印全部进程信息
ps -efH #树形结构显示
ps -efo pid #查看某些信息
打印结果:
[root@localhost ~]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Feb02 ? 00:00:04 /usr/lib/systemd/systemd --switched-root --system --deserialize 24
root 2 0 0 Feb02 ? 00:00:00 [kthreadd]
root 3 2 0 Feb02 ? 00:00:00 [ksoftirqd/0]
root 5 2 0 Feb02 ? 00:00:00 [kworker/0:0H]
root 7 2 0 Feb02 ? 00:00:00 [migration/0]
root 8 2 0 Feb02 ? 00:00:00 [rcu_bh]
root 9 2 0 Feb02 ? 00:00:00 [rcuob/0]
root 10 2 0 Feb02 ? 00:00:00 [rcuob/1]
top -d 1 //指定刷新时间为1s
top -n 2 //刷新两次结束
k pid enter //终止某一进程
u username enter //查看指定用户进程
Tasks: 29 total 进程总数
1 running 正在运行的进程数
28 sleeping 睡眠的进程数
0 stopped 停止的进程数
0 zombie 僵尸进程数
Cpu(s): 0.3% us 用户空间占用CPU百分比
1.0% sy 内核空间占用CPU百分比
0.0% ni 用户进程空间内改变过优先级的进程占用CPU百分比
98.7% id 空闲CPU百分比
0.0% wa 等待输入输出的CPU时间百分比
0.0% hi
0.0% si
Mem: 191272k total 物理内存总量
173656k used 使用的物理内存总量
17616k free 空闲内存总量
22052k buffers 用作内核缓存的内存量
Swap: 192772k total 交换区总量
0k used 使用的交换区总量
192772k free 空闲交换区总量
123988k cached 缓冲的交换区总量。
[root@localhost ~]# pidof bash
12680 966
1.getpid()函数以及getppid()函数
#include
#include
#include
int main()
{
printf("pid: %d\n", getpid());
printf("ppid: %d\n", getppid());
return 0;
}
#include
#include
#include
int main()
{
int ret = fork();
if(ret < 0){
perror("fork");
return 1;
}
else if(ret == 0){ //child
printf("I am child : %d!, ret: %d\n", getpid(), ret);
}else{ //father
printf("I am father : %d!, ret: %d\n", getpid(), ret);
}
sleep(1);
return 0;
}
#include
pid_t fork(void);
返回值:
子进程中返回0
父进程返回子进程id
出错返回-1
fork函数被调用一次将返回两次,在子进程中返回0,在父进程中返回子进程的ID。
子进程获得父进程的数据空间、堆、栈副本
#include
#include
#include
#include
#include
#include
int globvar=6;//全局变量
char buf[]="hello world\r\n";
int main( )
{
int var;//栈上变量
pid_t pid;
var = 88;
int *ptr=(int *)malloc(sizeof(int));
*ptr=2;
if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1)
{
printf("write error\r\n");
return -1;
}
printf("before fork\r\n");
if((pid=fork())<0)
{
printf("fork error");
return -1;
}
else if(pid==0)//child
{
++*ptr;
++var;
++globvar;
}
else//parent
{
sleep(2);
}
printf("pid = %ld, globvar = %d, &var = %ld , var = %d , *ptr = %d , ptr=%ld\r\n",(long)getpid(),globvar,(long)&var, var ,*ptr,(long)ptr);
free(ptr);
return 0;
}
运行结果:
hello world
before fork
pid = 15694, globvar = 7, &var = 140737488348208 , var = 89 , *ptr = 3 , ptr=6299664
pid = 15690, globvar = 6, &var = 140737488348208 , var = 88 , *ptr = 2 , ptr=6299664
我们看到地址都是一样的,但是值不一样,说明子进程中发生了拷贝,但是为什么地址一样呢?
这里涉及到物理地址和逻辑地址(或称虚拟地址)的概念。
在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同, 但其对应的物理空间是同一个。
当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间,
由于两者执行的代码不同,子进程的代码段也会分配单独的物理空间。
fork之后内核会通过将子进程放在队列的前面,以让子进程先执行,以免父进程执行导致写时复制,而后子进程执行exec系统调用,因无意义的复制而造成效率的下降。
fork时子进程获得父进程数据空间、堆和栈的复制,所以变量的地址(当然是虚拟地址)也是一样的。
每个进程都有自己的虚拟地址空间,不同进程的相同的虚拟地址显然可以对应不同的物理地址。因此地址相同(虚拟地址)而值不同。
fork常规用法
#include
#include
int main() {
pid_t id = fork();
if(id < 0){
perror("fork");
return 1;
}
else if(id > 0){
parent printf("parent[%d] is sleeping...\n", getpid());
sleep(30);
}
else{
printf("child[%d] is begin Z...\n", getpid());
sleep(5);
exit(EXIT_SUCCESS);
}
return 0;
}
在这里插入代码片