Linux内核设计与实现 读书笔记 转
Linux内核设计与实现 读书笔记:
http://www.cnblogs.com/wang_yb/tag/linux-kernel/
http://blog.csdn.net/yrj/article/category/718110
第一篇 内存的测量
2.1. 系统当前可用内存
- # cat /proc/meminfo
MemTotal: 8063544 kB
MemFree: 900952 kB
Buffers: 1183596 kB
Cached: 1596808 kB
MemTotal:总共可用物理内存
Buffers:主要是用来给 Linux 系统中块设备做缓冲区
Cached:用来缓冲我们所打开的文件(Linux 的思想是,如果内存充足,不用白不用,它会使用内存来 cache 一些文件,从而加快进程的运行速度;当内存不足时,这些内存又会被回收,供程序使用。)
所以真正可用的内存 = MemFree + Buffers + Cached
被用掉的物理内存 = MemTotal - 真正可用的内存
- # ls /proc
- 1 1139 1536 1832 2042 2089 2151 2257 2647 313 4 4407 63 901 bus iomem modules sysrq-trigger
- 10 12 1541 1833 2043 2090 2155 22806 26820 32 40 47 6996 902 cgroups ioports mounts sysvipc
- 1003 1263 1661 1861 2045 2098 2172 22961 27 323 41 48 7 932 cmdline irq mtrr timer_list
- # ls /proc/1139
- attr cmdline environ io maps mountstats oom_score sched stack syscall
auxv coredump_filter exe latency mem net pagemap schedstat stat task
cgroup cpuset fd limits mountinfo numa_maps personality sessionid statm wchan
clear_refs cwd fdinfo loginuid mounts oom_adj root smaps status - # cat status
数字代表着一个个目录;同时这些数字也与当前系统中运行进程的 PID 一一对应。在这些目录下面的文件,记录着这些进程在 Linux 内核中相应的数据。其中status记录了一些比较有用的信息,而oom_adj是OOM机制的重要参考。
2.2. 虚拟内存与物理内存
malloc只是分配了虚拟内存,kernel 不会分配物理页面给进程。
strcpy一类操作时,进程需要使用这块内存了,kernel 会产生一个页故障,从而为系统分配一个物理页面。
kernel 分配物理内存的最小单位为一个物理页面,一个物理页面为(4K Byte)
- # cat statm
- 345 87 74 1 0 58 0
这里有 7 个数,它们以页(4K)为单位。
Size (total pages,345) 任务虚拟地址空间的大小
Resident(pages,87) 应用程序正在使用的物理内存的大小
Shared(pages,74) 共享页数
Trs(pages,1) 程序所拥有的可执行虚拟内存的大小
Lrs(pages,0) 被映像到任务的虚拟内存空间的库的大小
Drs(pages,58) 程序数据段和用户态的栈的大小
dt(pages,0) 脏页数量(已经修改的物理页面),这个数一些系统可能修改成直接返回0了
其中Size Trs Lrs Drs对应于进程的虚拟内存,Resident shared dr对应于物理内存
- #cat maps
- 00008000-00009000 r-xp 00000000 1f:12 288 /mnt/msc_int0/hello // 该段内存地址对应于进程的代码段,4k
- 00010000-00011000 rw-p 00000000 1f:12 288 /mnt/msc_int0/hello // 该段内存地址对应与进程的数据段,4k
- 00011000-00032000 rwxp 00011000 00:00 0 // heap,132k
- 40000000-40002000 rw-p 40000000 00:00 0 //
- 41000000-41017000 r-xp 00000000 1f:0d 817360 /lib/ld-2.3.3.so
- 4101e000-41020000 rw-p 00016000 1f:0d 817360 /lib/ld-2.3.3.so
- 41028000-41120000 r-xp 00000000 1f:0d 817593 /lib/libc-2.3.3.so
- 41120000-41128000 ---p 000f8000 1f:0d 817593 /lib/libc-2.3.3.so
- 41128000-41129000 r--p 000f8000 1f:0d 817593 /lib/libc-2.3.3.so
- 41129000-4112c000 rw-p 000f9000 1f:0d 817593 /lib/libc-2.3.3.so
- 4112c000-4112e000 rw-p 4112c000 00:00 0
- befeb000-bf000000 rwxp befeb000 00:00 0 // stack, 84K
00008000-00009000 r-xp 00000000 1f:12 288 /mnt/msc_int0/hello分别对应:
内存段虚拟地址起始,权限,偏移量,映射文件的主设备号和次设备号,映射文件节点号,映像文件的路径。
我们可以通过 cat /proc/devices 来查看指定映射文件的主设备号的设备信息。
32位操作系统每个进程4G虚拟内存,由上图可知:0x00000000-0xbfffffff,用户空间3G;0xc0000000-0xffffffff,内核空间1G
实际物理内存如下:
- #cat memmap // 这个命令不一定每个linux版本都有,没有的话可能要自己写驱动
- 2 // 对应cat maps第一行,也就是进程的代码段
1 // 对应cat maps第二行,也就是进程的数据段
100000000000000000000000000000000 // 33个字符,对应132k内存,仅第一页实际使用了
11
4949494949494949491649494949494949494949494949
11
4917171717111617171717171717174949 0 049 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 049 0 0 0
0 0 0 0 0 0 0 044 042424242 0 0 0 041 0 0 0 0 0 0 0 0 0 0 0 0 0 04847 0 0 0 0 0 0 0
04747484949494949494949 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 049 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 04849 0 0 0 04849 0 0 047 049 0 0 0 0 0 0 0 0 0 0 04949 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 046 0 0 0 0 0 0 0 0 0 0 0 0 0 044 0
000000000
00000000
49
111
11
000000000000000000011
每个数字对应内存的一个页面(4k),如果为0,表示该页面空闲。其中代码段系统共享,数据段,堆栈是每个进程私有的。
2.3 关于交换分区和内存回收
之所以移动设备不采用交换分区:
1)交换分区会导致整体性能会下降很多
2)嵌入式设备一般使用 Flash 做为存储介质, Flash 写的次数是有限的。而如果在 Flash 上面建立交换分区的话,必然导致对 Flash 的频繁写,进而影响 Flash 的寿命
内存回收机制:
在 Linux 物理内存,每个页面有一个 dirty 的标志,如果该页面被改写了,我们称之为 dirty page。非dirty page都可以回收。也就是说,一个进程的代码段全部可以回收,数据段视情况而定,堆栈实际分配的物理内存均不能回收。
第二章 内存的优化
2.4 进程
一个进程运行时,所占的内存除了堆栈外,还包括:
全局变量、静态变量:初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。(数据段)
文字常量:常量字符串就是放在这里的,程序结束后由系统释放。(代码段)
程序代码:存放函数体的二进制代码。(代码段)
堆段:
malloc、free、new、delete 是我们从程序的角度去看待堆内存;而在 Linux 内核中会专门为进程分配一段内存地址,用来存放堆的内容;随着进程申请内存的增加,进程会通过系统调用brk,来让Linux内核扩展这段内存空间,从而分配给进程更多的内存;当进程释放内存时,进程又会通过系统调用brk,来告诉内核缩减这段内存空间,Linux 内核便会将其一部分物理内存进行回收。
由于用户态进程申请内存是以字节为单位,而在内核中内存的管理是以页面(4K)为单位;如何减少brk次数成为提升系统性能的一个关键。
堆内分配内存最少为16个字节,以8位对齐,也就是说16位,24位,32位,以此类推。
char* p;
p = malloc(20);
那么,实际分配的大小会写在:*(p-4),具体内存分布为:
*(p-5): prev_size
*(p-4): size
*(p-3): 标志位
*(p-2): M值。M=1表示该内存块通过mmap来分配,只有在分配大块内存时,才采用mmap的方式,那么在释放时会的munmap_chunk()去释放;否则,释放时由chunk_free()完成。实际上在glibc的内存管理中,采用brk的方式,只能管理1G 地址空间以下的内存,如果大于了1G,glibc 将采用mmap的方式,为堆申请一块内存。brk用于更改堆顶地址,而mmap则为进程分配一块虚拟地址空间。
*(p-1): P值。P=0,表示上一块空闲,这时prev_size通常为上一块的大小;P=1,表示上一块正在被使用,这时prev_size通常为0。
为了提高速度,glibc的malloc实现了fastbins,可以通过mallopt(M_MXFAST, value)来设置其伐值。对于所有小于M_MXFAST阀值的小块内存释放时,不会去尝试合并,还会被复用;大于M_MXFAST的会尝试合并和复用。M_MXFAST阀值设为0相当于禁用fastbins功能,也就是说会一直尝试合并和复用内存。总体来说,M_MXFAST对于内存使用的影响没有一个定论,但它肯定会加快进行的运行速度。
大块内存分配:
大块内存分配以后,通过查看 maps 文件,你可以发现增加一段线性区(也就是多了一行)。其权限为 rw-p。与进程缺省堆内存的权限rwxp是不同的。
一些阀值的设置方式也是调用mallopt。取值分别为M_MMAP_THRESHOLD、M_MMAP_MAX。
M_MMAP_THRESHOLD
libc中大块内存阀值,大于该阀值的内存申请,内存管理器将使用mmap系统调用申请内存;如果小于该阀值的内存申请,内存管理其使用brk系统调用来扩展堆顶指针。该阀值缺省值为128kB。
M_MMAP_MAX
该进程中最多使用mmap分配地址段的数量。设为0表示该进程禁用mmap功能。默认值为65536。
内存释放:
在libc中,只有当堆顶有连续的128k空闲内存时,libc才会掉用brk,来通知内核释放这段内存,将其返还给系统。这个默认的128k触发条件可以通过mallopt修改M_TRIM_THRESHOLD来改变。
M_TRIM_THRESHOLD
堆顶内存回收阀值,当堆顶连续空闲内存数量大于该阀值时,libc的内存管理其将调用系统调用brk,来调整堆顶地址,释放内存。该值缺省为128k。
M_TOP_PAD
该参数决定了,当libc内存管理器调用brk释放内存时,堆顶还需要保留的空闲内存数量。该值缺省为 0.
内存空洞:
其实是由于linux内存分配释放机制导致的。只要堆顶没释放,下面的释放将不会实质上真正释放。
应对策略:1)调低mmap阀值,用mmap,代价是,会多次调用系统调用(mmap和unmmap),使进程整体性能下降。
2)尽量优先释放堆顶内存。代码习惯问题,比较难以彻底解决。
内存空洞和内存泄漏是有区别的,后者会一直增加,前者增加到一定地步趋于稳定。
2.4 内存的跟踪
使用 mtrace 检测内存泄漏
1、 引入头文件 #include
2、 在需要跟踪的程序中需要包含头文件,而且在main()函数的最开始包含一个函数调用:mtrace()。由于在main 函数的最开头调用了mtrace(),所以该进程后面的一切分配和释放内存的操作都可以由mtrace来跟踪和分析。
3、 在运行进程前定义一个环境变量,用来指示一个文件。该文件用来输出 log 信息。如下的例子:
$ export MALLOC_TRACE=mymemory.log
4、 正常运行程序。此时程序中的关于内存分配和释放的操作都可以记录下来。
Linux内核设计与实现 读书笔记 转的更多相关文章
- Linux内核设计与实现 读书笔记
第三章 进程管理 1. fork系统调用从内核返回两次: 一次返回到子进程,一次返回到父进程 2. task_struct结构是用slab分配器分配的,2.6以前的是放在内核栈的栈底的:所有进程的ta ...
- Linux内核设计与实现读书笔记(8)-内核同步方法【转】
转自:http://blog.chinaunix.net/uid-10469829-id-2953001.html 1.原子操作可以保证指令以原子的方式执行——执行过程不被打断.内核提供了两组原子操作 ...
- Linux内核设计与实现——读书笔记2:进程管理
1.进程: (1)处于执行期的程序,但不止是代码,还包括各种程序运行时所需的资源,实际上进程是正在执行的 程序的实时结果. (2)程序的本身并不是进程,进程是处于执行期的程序及其相关资源的总称. (3 ...
- Linux内核设计与实现——读书笔记1:内核简介
内核:有的时候被称管理者或者操作系统核心,通常内核负责响应中断的中断服务程序, 负责管理多个进程从而分享处理器时间的调度程序,负责管理进程地址空间德内存管理程序 和网络,进程间通信等系统服务程序共同组 ...
- 初探内核之《Linux内核设计与实现》笔记上
内核简介 本篇简单介绍内核相关的基本概念. 主要内容: 单内核和微内核 内核版本号 1. 单内核和微内核 原理 优势 劣势 单内核 整个内核都在一个大内核地址空间上运行. 1. 简单.2. 高效 ...
- Linux内核架构与底层--读书笔记
linux中管道符"|"的作用 命令格式:命令A|命令B,即命令1的正确输出作为命令B的操作对象(下图应用别人的图片) 1. 例如: ps aux | grep "tes ...
- Linux内核设计第十七章笔记
第十七章 设备与模块 关于设备驱动和设备管理,四种内核成分 设备类型:在所有unix系统中为了统一普通设备的操作所采用的分类 模块:Linux内核中用于按需加载和卸载目标代码的机制 内核对象:内核数据 ...
- Linux内核分析 一二章读书笔记
第一章 Linux内核简介 1.Unix (1)Unix系统很简洁 (2)在Unix中,所以东西都被当作文件对待,通过一套相同的系统调用接口来进行:open(),read(),write(),lsee ...
- 《Linux内核设计与实现》笔记-1-linux内核简单介绍
一.Linux内核相对于传统的UNIX内核的比較: (1):Linux支持动态内核模块. 虽然Linux内核也是总体式结构,但是同意在须要的时候动态哦卸除(rmmod xxx)和载入内核模块(insm ...
随机推荐
- PHP正则表达式匹配中文字符
网上有很多类似的文章,但往往都不能用 所以记录一下 preg_match_all("/([\x{4e00}-\x{9fa5}])/u", $input, $match); 注意:限 ...
- JS获得月最后一天和js得到一个月最大天数
<html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>标题页</title ...
- html5 canvas 移动小方块
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- Chef
Chef是一个渐渐流行的部署大.小集群的自动化管理平台.Chef可以用来管理一个传统的静态集群,也可以和EC2或者其他的云计算提供商一起使用.Chef用cookbook作为最基本的配置单元,可以被泛化 ...
- ControlsFX8.0.2中对话框无法判断是否显示的修改
在org.controlsfx.dialog.FXDialog.java中加入 public abstract boolean isShowing(); 在org.controlsfx.dialog. ...
- quora 中有关angular与emberjs的精彩辩论
原贴地址,要注册才能看,这里只有国人翻译的一部分内容 本文源自于Quora网站的一个问题,作者称最近一直在为一个新的Rails项目寻找一个JavaScript框架,通过筛选,最终纠结于Angular. ...
- hdu 1199 Color the Ball
http://acm.hdu.edu.cn/showproblem.php?pid=1199 Color the Ball Time Limit: 2000/1000 MS (Java/Others) ...
- POJ1463 Strategic game (最小点覆盖 or 树dp)
题目链接:http://poj.org/problem?id=1463 给你一棵树形图,问最少多少个点覆盖所有的边. 可以用树形dp做,任选一点,自底向上回溯更新. dp[i][0] 表示不选i点 覆 ...
- 转载sublime text3中package Control
Sublime Text 3 安装Package Control 原来Subl3安装Package Control很麻烦,现在简单的方法来了 一.简单的安装方法 使用Ctrl+`快捷键或者通过View ...
- AFNetWorking3.0使用 自签名证书的https请求
前几日,项目组出于安全角度的考虑,要求项目中的请求使用https请求,因为是企业内部使用的app,因此使用了自签名的证书,而自签名的证书是不受信任的,所以我们就需要自己来做证书的验证,包括服务器验证客 ...