程序员的自我修养-链接、装载与库读书笔记
温故而知新
为什么系统内存分段、分页?
直接将物理内存分配给进程使用存在三个问题:* 地址空间不隔离 所有程序都直接访问物理地址,程序所使用的内存空间不是相互隔离的,恶意程序会撰改其他程序的内存数据达到破坏的目的 * 内存使用效率低 * 程序运行的地址不确定
解决上面存在的问题采用了一种间接访问地址的方法:虚拟地址
分段:把一段程序所需要的内存空间大小的虚拟空间映射到某个地址空间。这样可以达到程序与地址空间隔离不会访问别的程序的内存。
同时也解决程序运行地址不确定问题但是这样子会有一个问题,当内存不够用时被换入换出到磁盘的都是整个程序势必会降低效率。 所以我们需要进行粒度更小的换入换出。
分页:分页就是解决分段的大粒度问题。把地址空间认为的等分成固定大小的页,每一页的大小有硬件决定,或者硬件支持多种大小
的页,由操作系统选择决定页的大小。但同一时刻只能选择一种大小,所以对与整个操作系统来说页就是固定的。
什么是线程?
线程 有时被称为轻量级进程,是程序执行的最小单元。一个标准的线程有线程ID、当前指令指针(PC)、寄存器集合、堆栈组成。
同一个进程的所有线程之间共享程序的内存空间(包括代码段、数据段、堆等)及一些进程级的字段(如打开的文件、信号)。 线程页拥有自己的私有存储空间 * 栈,一般情况下认为私有的数据 * 线程局部存储 (TLS) * 寄存器(包括PC)
|线程私有|线程之间共享|
|——-|———|
|局部变量|全局变量|
|函数参数|堆上的数据|
|TLS |函数里的静态变量|
| |程序代码任何线程都有权利读取并执行任何代码|
| |打开的文件,A线程打开的文件可以由B线程读写|同步与锁
|类型|说明|适用场合|
|—|—-|——|
|二元信号量|最简单的锁,只有两种状态:占用与非占用;|适合被唯一一个线程独占访问的地资源|
|多元信号量|简称信号量(semaphore)|允许有多个线程访问|
|互斥量(Mutex)|与二次元类似,但是信号量可以被系统中的一个线程获取之后由另外一个线程释放;而互斥量,要求谁获取就是负责释放|资源近同时允许一个线程访问|
|临界区(critical section)|比互斥量更为严格的同步手段;一个进程创建了一个互斥量或者信号量,另一个进程试图区获取该锁是合法的|仅限于本进程,其他进程无法获取该锁|
|读写锁(read-write lock)|有两种获取方式:共享、独占||
|条件变量(condition variable)|一个条件变量可以被多个线程等待;线程可以唤醒条件变量,此时所有等待条件变量的线程都会被唤醒||
目标文件里有什么
目标文件
程序编译完成之后主要分为两种段:程序指令和程序数据- 一般而言c编译的可行语句都编译成机器代码保存在
.text
段 (程序指令
) - 已初始化的全局变量和局部静态变量都保存在
.data
段(虽然位初始化的全局变量、局部静态变量默认值都是0,没必要放在这里浪费内存)(程序数据
) - 未初始化的全局变量和局部静态变量一般存放在
.bss
段(只是未这些变量预留位置而已,所以在文件中不占据空间(程序数据
) C/C++中,编译器默认为函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号。
1
__attribute__((week))
1
2
3
4
5
6
7
8extern int ext;
int weak;
int strong=1;
__attribute__((weak)) weak2=2;
int main()
{
return 0;
}
- 一般而言c编译的可行语句都编译成机器代码保存在