《Linux/Unix系统编程手册》读书笔记3
第6章
这章讲进程、虚拟内存和环境变量等。
进程是一个可执行程序的实例。一个程序可以创建很多进程。
进程是由内核定义的抽象实体,内核为此实体分配执行程序所需的系统资源。
从内核的角度来看,进程是由用户内存空间和内核数据结构组成的。程序的代码和代码中的变量存放在用户内存空间,内核数据结构用于维护进程状态信息。
对于每个进程都有一个唯一的进程号(进程ID)(正数),用来标识系统中的某个程序。
getpid(),返回调用该函数的进程的进程ID。
#include <unistd.h> pid_t getpid(void);
总是成功调用并返回调用该函数的进程的进程ID。
getppid(),返回自己的父进程的进程ID。
#include <unistd.h> pid_t getppid(void);
总是成功调用并返回该函数的父进程的ID。
PS:所有进程的始祖为init进程(进程ID为1)。
内存布局:
Linux/x86-32进程内存结构如下:
文本段存放着程序运行的机器语言指令,具有只读属性,防止进程通过错误指针修改自身指令。
初始化数据段存在着显式初始化的全局变量和静态变量。
未初始化数据段存放着未进行显式初始化的全局变量和静态变量。将已经初始化的全局变量和静态变量与未进行初始化的全局变量和静态变量分开存放是因为程序在存放在磁盘上没有必要为未初始化的变量分配存储空间,只需要记录未初始化数据段的位置和大小,在程序运行的时候再分配空间。
堆(heap)是在运行时为变量动态进行内存分配的区域,堆顶叫program break,后面一章就是通过brk()和sbrk()来调整堆的大小进而来分配内存(malloc()就是基于这两个函数实现)。
栈(stack)由栈帧组成的,可以动态增长和收缩的段,系统为每个当前调用的函数分配一个栈帧,里面存储了函数的局部变量(自动变量)。
通过虚拟内存管理技术可以高效的使用CPU和RAM资源。因为大多数都有两个局部性:空间局部性和时间局部性。
虚拟内存将每个程序使用的内存分割成小块、固定大小的页单元。对于RAM,将其划分成一系列与虚拟内存页面大小相同的页帧。在程序运行的时候,只有一部分的页驻留在物理内存页帧中,当进程需要访问的页面不在物理内存中,就会发生页面错误,并挂起进程的执行,再将页面从磁盘载入到物理内存。
内核为每个进程维护一张页表,通过页表可以虚拟地址对应的物理地址。
虚拟内存的实现需要硬件有分页内存管理单元(将虚拟内存地址转成相应的物理内存地址)。
通过虚拟内存管理可以将虚拟地址空间与RAM物理地址空间隔开:使进程与进程、进程与内核相互隔离,可以保护进程和内核的内存;可以使得多个进程共享内存;实现内存保护机制;程序员和一些程序无需关注程序在物理内存的布局;还可以提高CPU利用率。
命令行参数:
int argc; 命令行参数个数;
char *argv[];指向命令行参数的指针数组;
PS:这两个参数是main()函数的局部变量,所以其他函数要使用这两个参数需要进行传递或者设置一个指向argv的全局变量。
环境列表:
每个进程都有与自己相关的环境列表。
每条记录的形式为name=value;
新进程创建时会继承父进程的环境副本(原始的进程间通信方式)。
可以通过printenv输出当前的环境列表:
lancelot@debian:~$ printenv
SSH_AGENT_PID=
CLUTTER_IM_MODULE=ibus
GPG_AGENT_INFO=/home/lancelot/.cache/keyring-A5CMa0/gpg::
TERM=xterm
SHELL=/bin/bash
XDG_SESSION_COOKIE=66aede8f90c2ace983c1e18451c8875a-1397554660.783480-
HUSHLOGIN=FALSE
GNOME_KEYRING_CONTROL=/home/lancelot/.cache/keyring-A5CMa0
LC_ALL=zh_CN.UTF-
USER=lancelot
LIBGL_DRIVERS_PATH=/usr/lib/i386-linux-gnu/dri:/usr/lib/x86_64-linux-gnu/dri
LS_COLORS=rs=:di=;:ln=;:mh=:pi=;:so=;:do=;:bd=;;:cd=;;:or=;;:su=;:sg=;:ca=;:tw=;:ow=;:st=;:ex=;:*.tar=;:*.tgz=;:*.arj=;:*.taz=;:*.lzh=;:*.lzma=;:*.tlz=;:*.txz=;:*.zip=;:*.z=;:*.Z=;:*.dz=;:*.gz=;:*.lz=;:*.xz=;:*.bz2=;:*.bz=;:*.tbz=;:*.tbz2=;:*.tz=;:*.deb=;:*.rpm=;:*.jar=;:*.war=;:*.ear=;:*.sar=;:*.rar=;:*.ace=;:*.zoo=;:*.cpio=;:*.7z=;:*.rz=;:*.jpg=;:*.jpeg=;:*.gif=;:*.bmp=;:*.pbm=;:*.pgm=;:*.ppm=;:*.tga=;:*.xbm=;:*.xpm=;:*.tif=;:*.tiff=;:*.png=;:*.svg=;:*.svgz=;:*.mng=;:*.pcx=;:*.mov=;:*.mpg=;:*.mpeg=;:*.m2v=;:*.mkv=;:*.webm=;:*.ogm=;:*.mp4=;:*.m4v=;:*.mp4v=;:*.vob=;:*.qt=;:*.nuv=;:*.wmv=;:*.asf=;:*.rm=;:*.rmvb=;:*.flc=;:*.avi=;:*.fli=;:*.flv=;:*.gl=;:*.dl=;:*.xcf=;:*.xwd=;:*.yuv=;:*.cgm=;:*.emf=;:*.axv=;:*.anx=;:*.ogv=;:*.ogx=;:*.aac=;:*.au=;:*.flac=;:*.mid=;:*.midi=;:*.mka=;:*.mp3=;:*.mpc=;:*.ogg=;:*.ra=;:*.wav=;:*.axa=;:*.oga=;:*.spx=;:*.xspf=;:
DESKTOP_AUTOSTART_ID=10dc1ad7011f06891f139755466392940400000043790001
SSH_AUTH_SOCK=/home/lancelot/.cache/keyring-A5CMa0/ssh
SESSION_MANAGER=local/debian:@/tmp/.ICE-unix/,unix/debian:/tmp/.ICE-unix/
PATH=/home/lancelot/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/lancelot/bin
MAIL=/var/mail/lancelot
LC_COLLATE=C
PWD=/home/lancelot
XMODIFIERS=@im=ibus
LANG=zh_CN.UTF-
HOME=/home/lancelot
SHLVL=
LANGUAGE=zh_CN.UTF-:zh:en_US:en
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
LOGNAME=lancelot
XDG_DATA_DIRS=/usr/share/gnome:/usr/local/share/:/usr/share/
QT4_IM_MODULE=ibus
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-q3rPwh3OMI,guid=5495fcf0de26e09259bc54ef534cfde4
WINDOWPATH=
TEXTDOMAIN=im-config
DISPLAY=:
GTK_IM_MODULE=ibus
TEXTDOMAINDIR=/usr/share/locale/
XAUTHORITY=/home/lancelot/.Xauthority
_=/usr/bin/printenv
getenv(),获得进程环境的值
#include <stdlib.h> char *getenv(const char *name);
对于存在name的环境变量就返回对应的value的指针,如果不存在就返回NULL
putenv(),修改环境变量
#include <stdlib.h> int putenv(char *string);
将name=value形式的字符串添加到当前的环境列表。成功返回0,失败返回非0值。
PS:putenv是将environ变量的某个元素指向string指向的位置,并不是指向string指向字符串的副本。所以如果修改string指向的内容,环境变量也会改变,因此string指向后来不能是自动变量。
PS:当string里不包含等号的时候,将会在环境列表移除string命名的环境变量。
setenv(),往环境添加变量
#include <stdlib.h> int setenv(const char *name, const char *value, int overwrite);
name,value与name=value对应,overwrite决定时候改变环境。如果以name标识的变量存在环境里而且overwrite为0,就不改变环境;否则如果overwrite不为0就总是改变环境。
成功返回0, 失败返回-1
PS:不同与putenv,setenv是分配一块内存缓冲区,将name和value指向的字符串复制到缓冲区里。
unsetenv(),移除环境变量
#include <stdlib.h> int unsetenv(const char *name);
移除name标识的变量
成功调用返回0,失败返回-1。
clear(),清除整个环境
#define _BSD_SOURCE
#include <stdlib.h> int clearenv(void);
成功调用返回0,失败返回非0值。
PS:setenv和clearenv会导致内存泄露:setenv分配了一块内存缓冲区,但是clearenv没有释放这个缓冲区。
-----------------省略setjmp()和longjump(),非局部跳转(不同于goto,可以从一个函数跳转到另一个函数)------------
自己比较少使用。。。。还有整整一本下册啊。。。今天面试被虐了。。。
要继续认真看这本书。。。后台开发不容易做啊。。。。。。。。。。。。
----------------中间吐槽完毕-------------------------------------------------------------------------------------------------------------
练习:
6-1:编译程序清单6-1的程序,使用ls -l 命令显示可执行文件的大小。虽然程序包含一个大约10MB的数组,但可执行文件大小远小于此,为什么?
程序清单如下:
/*
* =====================================================================================
*
* Filename: mem_segment.c
*
* Description:
*
* Version: 1.0
* Created: 2014年03月19日 00时03分10秒
* Revision: none
* Compiler: gcc
*
* Author: alan (), alan19920626@gmail.com
* Organization:
*
* =====================================================================================
*/ #include <stdio.h>
#include <stdlib.h> char globBuf[];
int primes[] = {, , , }; static int square(int x){
int result; result = x * x;
return result;
} static void doCal(int val){
printf("The square of %d is %d\n", val, square(val)); if(val < ){
int t; t = val * val * val;
printf("The cube of %d is %d\n", val, t);
}
} int main(int argc, char *argv[]){
static int key = ;
static char mbuf[];
char *p; p = (char *)malloc(); doCal(key); exit(EXIT_SUCCESS);
}
6-1
结果如下:
lancelot@debian:~/Code/tlpi$ gcc -o mem_segments mem_segment.c
lancelot@debian:~/Code/tlpi$ gvim mem_segment.c
lancelot@debian:~/Code/tlpi$ ls -l mem_segments
-rwxr-xr-x lancelot lancelot 4月 : mem_segments
因为那个10MB的数组(静态)没有初始化,所以是存放在未初始化的数据,只有在运行的时候再为其分配内存。
6-3:使用getenv()函数,和putenv()函数,必要时可以直接修改environ,来实现setenv()函数和unsetenv()函数。(结合6-4程序清单)
/*
* =====================================================================================
*
* Filename: 6-3.c
*
* Description:
*
* Version: 1.0
* Created: 2014年04月11日 15时30分32秒
* Revision: none
* Compiler: gcc
*
* Author: alan (), alan19920626@gmail.com
* Organization:
*
* =====================================================================================
*/ #define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include "tlpi_hdr.h" extern char **environ;
char env[]; int M_setenv(const char *name, const char *value, int overwrite){
strcpy(env, name);
strcat(env, "=");
strcat(env, value); if(getenv(name) != NULL && overwrite == )
return ;
if(putenv(env) == )
return ;
else
return -;
} int M_unsetenv(const char *name){
if(putenv((char *)name) == )
return ;
return -;
} int main(int argc, char *argv[]){
int j;
char **ep; clearenv(); for(j = ; j < argc; j++)
if(putenv(argv[j]) != )
errExit("putenv: %s", argv[j]); if(M_setenv("GREET", "Hello world", ) == -)
errExit("M_setenv"); M_unsetenv("BYE"); for(ep = environ; *ep != NULL; ep++)
puts(*ep); exit(EXIT_SUCCESS);
}
6-4程序清单:
/*
* =====================================================================================
*
* Filename: modify_env.c
*
* Description:
*
* Version: 1.0
* Created: 2014年03月19日 10时48分04秒
* Revision: none
* Compiler: gcc
*
* Author: alan (), alan19920626@gmail.com
* Organization:
*
* =====================================================================================
*/ #define _GNU_SOURCE
#include <stdlib.h>
#include "tlpi_hdr.h" extern char **environ; int main(int argc, char * argv[]){
int j;
char **ep; clearenv(); for(j = ; j < argc; j++)
if(putenv(argv[j]) != )
errExit("putenv: %s", argv[j]); if(setenv("GREET", "Hello world", ) == -)
errExit("setenv"); unsetenv("BYE"); for(ep = environ; *ep != NULL; ep++)
puts(*ep); exit(EXIT_SUCCESS);
}
结果:
lancelot@debian:~/Code/tlpi$ ./- "GREET=Guten" SHELL=/bin/bash BYE=Ciao
GREET=Guten
SHELL=/bin/bash
lancelot@debian:~/Code/tlpi$ ./- SHELL=/bin/sh BYE=byebye
SHELL=/bin/sh
GREET=Hello world
PS:吐槽。。。。。。还要继续努力,努力成为一个后台开发。。。。。。。。。
《Linux/Unix系统编程手册》读书笔记3的更多相关文章
- HTTP权威指南读书笔记
HTTP权威指南笔记 读书有两种境界,第一种境界是将书读薄,另一种是读厚.本篇文章就是HTTP权威指南的读书笔记,算是读书的第一重境界,将厚书读薄.文章对HTTP的一些关键概念做了比较详细的概述,通读 ...
- css权威指南读书笔记
今天翻手机,翻到了许久之前看css权威指南时的笔记,遂移到博客中来. 1.属性选择器p.one class名为one的p元素p[class][name] 含有class和name属性的p元素p[cla ...
- 经典的性能优化最佳实践 web性能权威指南 读书笔记
web性能权威指南 page 203 经典的性能优化最佳实践 无论什么网络,也不管所用网络协议是什么版本,所有应用都应该致力于消除或减 少不必要的网络延迟,将需要传输的数据压缩至最少.这两条标准是经典 ...
- css权威指南读书笔记-第10章浮动和定位
这一章看了之后真是豁然开朗,之前虽然写了圣杯布局和双飞翼布局,有些地方也是模糊的,现在打算总结之后再写一遍. 以下都是从<css权威指南>中摘抄的我认为很有用的说明. 浮动元素 一个元素浮 ...
- Hadoop权威指南读书笔记
本书中提到的Hadoop项目简述 Common:一组分布式文件系统和通用I/O的组件与接口(序列化.javaRPC和持久化数据结构). Avro:一种支持高效.跨语言的RPC以及永久存储数据的序列化系 ...
- JavaScript权威指南读书笔记
JavaScript 1.变量 变量是一个表示值的符号,是一个名字,他的本质是值: var x; //----声明一个变量: 值通过等号“=”赋给变量,x = 16; 对象是名/值对的集合,或字符串到 ...
- Java性能优化权威指南-读书笔记(五)-JVM性能调优-吞吐量
吞吐量是指,应用程序的TPS: 每秒多少次事务,QPS: 每秒多少次查询等性能指标. 吞吐量调优就是减少垃圾收集器消耗的CPU周期数,从而将更多的CPU周期用于执行应用程序. CMS吞吐调优 CMS包 ...
- Java性能优化权威指南-读书笔记(四)-JVM性能调优-延迟
延迟指服务器处理一个请求所花费的时间,单位一般是ms.s. 本文主要讲降低延迟可以做的服务器端JVM优化. JVM延迟优化 新生代 新生代大小决定了应用平均延迟 如果平均Minor GC持续时间大于应 ...
- Java性能优化权威指南-读书笔记(三)-JVM性能调优-内存占用
新生代.老年代.永久代的概念不多说,这三个空间中任何一个不能满足内存分配请求时,就会发生垃圾收集. 新生代不满足内存分配请求时,发生Minor GC,老年代.永久代不满足内存分配请求时,发生Full ...
- Java性能优化权威指南-读书笔记(二)-JVM性能调优-概述
概述:JVM性能调优没有一个非常固定的设置,比如堆大小设置多少,老年代设置多少.而是要根据实际的应用程序的系统需求,实际的活跃内存等确定.正文: JVM调优工作流程 整个调优过程是不断重复的一个迭代, ...
随机推荐
- 学习Linux第六天
1.Shell编程 bash变量: 都是以字符串格式存储 x=5 等号左右不能有空格,会当作命令处理 如何调用: echo $x 此法无法进行数值运算,不存在的变量输出空 set -u 设置变量报错 ...
- 《我是一只IT小小鸟》阅读笔记
<我是一只IT小小鸟>,这本书对我来说,有可能我现在并不懂得那其中的道理,但是,我觉得它写的很好,很现在的我很相似,但是在里面,我看到了他们都在说,一开始可能并不对IT这门课有很深的见解, ...
- it小小鸟心得
本来打算就这么浑浑噩噩的过完我的大学四年生涯,但当我读完这本书,改变了我的想法.许多人说大学是最美好的,确实,在这里,我每天都不用认真听讲,不用准时去上课,可是久而久之,自己有感而发觉得这样碌碌无为下 ...
- Codeforces Round #353 (Div. 2) C Money Transfers
题目链接: http://www.codeforces.com/contest/675/problem/C 题意: 给一个数组,每个数与他相邻的数相连,第一个与最后一个相连,每个数的数值可以左右移动, ...
- 打造XP下可运行的微型PE文件
前几天和朋友交流技术,提到手工打造微型PE文件,他说现在网上流传的大部分版本在XP SP3下都不能运行,于是心血来潮,拍着胸脯说:“你放心,忙完了帮你做一个.”后来花了半天时间,终于打造出一个XP下可 ...
- URAL题解—不断跟新中
1014:简单题,忘了0的情况可以是10,== 1219:找呀找规律,满足N*(N-1)/2+1=X;就是1 的情况了
- 重构:CSS也面向对象
最初接触到面向对象的CSS还是因为项目中的CSS已经超过八千行,缺乏约束和管理,在近期或者是不远的将来,有迫切的要求需要重构.在前端重构中,我们已经讨论过了JavaScript面向对象的重构,在这个时 ...
- 使用jQuery动态加载js脚本
动态加载Javascript是一项非常强大且有用的技术.这方面的主题在本站已经讨论了不少,我也经常会在一些个人项目上使用RequireJS和Dojo加载js.它们很强大,但有时候也会得不偿失.如果你使 ...
- tomcat与IIS在多IP服务器下的支持
同一个服务器下,双IP(或更多IP),实现tomcat与IIS公用80端口. 操作其实也很简单的,首先禁用iis的套接字池,iis绑定一个ip,然后tomcat在绑定另一个ip,最后重启下服务器即可. ...
- Java 中最常见的 5 个错误
在编程时,开发者经常会遭遇各式各样莫名错误.近日,Sushil Das 在 Geek On Java上列举了 Java 开发中常见的 5 个错误,与君共「免」. 原文链接:Top 5 Common M ...