今天给各位分享linux脏页有多少个的知识,其中也会对linux 脏页进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:
1、linux进程列表中有多个top
一:ps命令
以下是 ps 的最简单形式:
$ ps
PID TTY TIME CMD
3884 pts/1 00:00:00 bash
3955 pts/2 00:00:00 more
3956 pts/5 00:00:05 sqlplus
• PID 是进程的标识号。
• TTY 是进程所属的终端控制台。
• TIME 列是进程所使用的总的 CPU 时间。
• CMD 列列出正在执行的命令行。
使用带有 -ef 选项的 ps,返回系统中所有用户的所有进程的完整列表。一般将此 ps 命令的结果传送到 grep 中,则该结果更易于查看。例如:
$ ps -ef | grep oracle
UID PID PPID C STIME TTY TIME CMD
oracle 1633 1 0 13:58 ?00:00:00 ora_pmon_ora1
oracle 1635 1 0 13:58 ?00:00:00 ora_dbw0_ora1
oracle 1637 1 0 13:58 ?00:00:01 ora_lgwr_ora1
oracle 1639 1 0 13:58 ?00:00:02 ora_ckpt_ora1
oracle 1641 1 0 13:58 ?00:00:02 ora_smon_ora1
oracle 1643 1 0 13:58 ?00:00:00 ora_reco_ora1
oracle 1645 1 0 13:58 ?00:00:00 ora_cjq0_ora1
oracle 1647 1 0 13:58 ?00:01:18 ora_qmn0_ora1
oracle 1649 1 0 13:58 ?00:00:00 ora_s000_ora1
oracle 1651 1 0 13:58 ?00:00:00 ora_d000_ora1
-e : 在命令执行后显示环境
-f : 完整显示输出
• 标为 C 的列是由 CPU 用于计算执行优先级的因子。
• STIME 是指进程的启动时间。
• 问号表示这些进程不属于任何 TTY,因为它们是由系统启动的。
主要参数说明:
1) 进程用户ID(UID),
虽然 uid 通常是指数字型的标识,但在第一列下指定的是用户名,标记为 UID
2) 进程ID (PID)
3) 父进程ID (PPID)
PPID 是父进程的标识号。对于 Oracle 进程,这里的标识号为 1 — 它是 init 进程(所有进程的父进程)的 id,因为在本系统中安装的 Oracle 是作为登录进程的一部分而启动的
4) CPU 调度情况 (C)
即是是由 CPU 用于计算执行优先级的因子。
5) 进程启动的时间 (STIME)
6) 进程共占用CPU的时间(TIME)
7) 启动进程的命令 (CMD)
8)问号表示这些进程不属于任何 TTY,因为它们是由系统启动的。
使用PS命令分析系统性能的方法主要有:
1) 首先,根据用户ID寻找由同一用户执行的许多相似任务,这些任务很可能是因为用户运行的某个脚本程序在后台启动多个进程而造成的。
2) 接下来,检查TIME域中各进程累计占用CPU的时间,如果有某个进程累计占用了大量的CPU时间,通常说明该进程可能陷入了无限循环,或该京城的某写逻辑出了错
3) 找到那些已陷入死锁的进程ID后,就可以使用kill命令强制终止该进程了。
二:top命令
Ps 只为您提供当前进程的快照。要即时查看最活跃的进程,可使用 top。
Top 实时地提供进程信息。它还拥有交互式的状态,允许用户输入命令,如 n 后面跟有 5 或 10 等数字。其结果是指示 top 显示 5 或 10 个最活跃的进程。Top 持续运行,直到您按 "q" 退出 top 为止。
Top中的几个隐含参数:
top中按1键和F键的参数:
按1键可以等到多个cpu的情况
按F(f:当前状态,可以按相应的字母键做top的定制输出)后得参数:
对F键和f键的区别:
如果进入F键区可以做进程显示的排序,如果进入f键区的话则可以选择显示的多个项目:
* A: PID = Process Id //进程ID
b: PPID = Parent Process Pid //父进程ID
c: RUSER = Real user name //真正的(Real)所属用户名称
d: UID = User Id //用户ID
e: USER = User Name //用户名称
f: GROUP = Group Name //组名称
g: TTY = Controlling Tty //控制
h: PR = Priority //优先权
i: NI = Nice value //优先级得值(负数代表较高的优先级,正数是较低的优先级.0标志改优先级的值是不会被调整的)
j: #C = Last used cpu (SMP) //随后使用的cpu比率
k: %CPU = CPU usage //cpu使用比率
l: TIME = CPU Time //cpu占用时间
m: TIME+ = CPU Time, hundredths //cpu%比
n: %MEM = Memory usage (RES) //内存使用率
o: VIRT = Virtual Image (kb) //虚拟镜像(VIRT = SWAP + RES:所有进程使用的虚拟内存值,包括所有的代码,数据,共享库已经被swapped out的)
p: SWAP = Swapped size (kb) //交换空间大小(所有虚拟内存中的镜像)
q: RES = Resident size (kb) //已经使用了的常驻内存(Resident size):RES = CODE + DATA
r: CODE = Code size (kb) //分配给执行代码的物理内存
s: DATA = Data+Stack size (kb) //data+stack:物理内存中非存放代码的空间,用于存放数据
t: SHR = Shared Mem size (kb) //共享内存大小.放映了一个task的潜在可以供别人使用的内存的大小
u: nFLT = Page Fault count //内存叶错误的数量
v: nDRT = Dirty Pages count //脏页的数量
w: S = Process Status //进程状态:( R )为运行或可执行的,( S )为该程序正在睡眠中,( T )正在侦测或者是停止了,( Z )僵尸程序
x: COMMAND = Command name/line //进程启动命令行参数
y: WCHAN = Sleeping in Function //在睡眠中
z: Flags = Task Flags //任务标志
Note1:
If a selected sort field can't be shown due to screen width or your field order, the '' and '' keys
will be unavailable until a field within viewable range is chosen.
Note2:
Field sorting uses internal values, not those in column display. Thus, the TTY WCHAN fields will violate strict ASCII collating sequence. (shame on you if WCHAN is chosen)
Current Fields: AEHIOQTWKNMbcdfgjplrsuvyzX for window 1:Def
Toggle fields via field letter, type any other key to return
* A: PID = Process Id
* E: USER = User Name
* H: PR = Priority
* I: NI = Nice value
* O: VIRT = Virtual Image (kb)
* Q: RES = Resident size (kb)
* T: SHR = Shared Mem size (kb)
* W: S = Process Status
* K: %CPU = CPU usage
* N: %MEM = Memory usage (RES)
* M: TIME+ = CPU Time, hundredths
b: PPID = Parent Process Pid
c: RUSER = Real user name
d: UID = User Id
f: GROUP = Group Name
g: TTY = Controlling Tty
j: #C = Last used cpu (SMP)
p: SWAP = Swapped size (kb)
l: TIME = CPU Time
r: CODE = Code size (kb)
s: DATA = Data+Stack size (kb)
u: nFLT = Page Fault count
v: nDRT = Dirty Pages count
y: WCHAN = Sleeping in Function
z: Flags = Task Flags
* X: COMMAND = Command name/line
Flags field:
0x00000001 PF_ALIGNWARN
0x00000002 PF_STARTING
0x00000004 PF_EXITING
0x00000040 PF_FORKNOEXEC
0x00000100 PF_SUPERPRIV
0x00000200 PF_DUMPCORE
0x00000400 PF_SIGNALED
0x00000800 PF_MEMALLOC
0x00002000 PF_FREE_PAGES (2.5)
0x00008000 debug flag (2.5)
0x00024000 special threads (2.5)
0x001D0000 special states (2.5)
0x00100000 PF_USEDFPU (thru 2.4)
2、Linux磁盘I/O子系统
上文学到 不管什么文件系统类型,都通过VFS(虚拟文件系统层)读和写等操作文件,写文件的元数据和文件的实际数据到磁盘 。但数据是怎么落地磁盘中的呢?落到磁盘中的都经过什么组件?
以一个写数据到磁盘为例,给出Linux I/O子系统的体系结构。
当磁盘执行写入操作时发生的 基本操作 (假设磁盘上扇区中的文件数据已经被读取到分页缓存)。
1) 一个进程通过write()系统调用 VFS虚拟文件系统 请求写一个文件。
2) 内核更新已映射文件的分页缓存。
3) 内核线程 pdflush/Per-BDI flush将分页缓存刷新到磁盘。
4) 同时 VFS虚拟文件系统层 在一个bio(block input output)结构中放置每个块缓冲,并向块设备层提交写请求。
5) 块设备层 从上层得到请求,并执行一个 I/O电梯操作,将请求放置到I/O 请求队列。
6) 设备驱动器 (比如SCSI 或 其他设备特定的驱动器)将执行写操作。
7) 磁盘设备 固件执行硬件操作,如在盘片扇区上定位磁头,旋转,数据传输。
过去的20年中,处理器性能的改进要超过计算机系统中的其他组件,如处理器缓存、物理内存及磁盘等等。 访问内存和磁盘的速度较慢会限制整个系统的性能 ,怎么解决这个问题呢?引入 磁盘缓存机制 ,在较快的存储器中缓存频繁使用的数据,减少了访问较慢的存储器的次数。
磁盘缓存机制有以下3个地方解决:
引入存储层次结构 ,在CPU和磁盘之间放置L1缓存、L2缓存、物理内存和一些其他缓存减少这种不匹配,从而让进程减少访问较慢的内存和磁盘的次数,避免CPU花费更多的时间等待来自较慢磁盘驱动器的数据。
另外一种解决思路: 在更快的存储器上实现更高的缓存命中率,就可能更快地访问数据 。怎么提高缓存命中率呢?引入 参考局部性(locality of reference) 的技术。这项技术基于以下2个原则:
1) 大多数最近使用过的数据,在不久的将来有较高的几率被再次使用(时间局部性)。
2) 驻留在数据附近的数据有较高的几率被再次使用(空间局部性)。
Linux在许多组件中使用这些原则,比如分页缓存、文件对象缓存(索引节点缓存、目录条目缓存等等)、预读缓冲等。
以进程从磁盘读取数据并将数据复制到内存的过程为例。进程可以从缓存在内存中的数据副本中检索相同的数据,用于读和写。
1) 进程写入新数据
当一个进程试图改变数据时,进程首先在内存中改变数据。此时磁盘上的数据和内存中的数据是不相同的,并且内存中的数据被称为 脏页(dirty page) 。脏页中的数据应该尽快被同步到磁盘上,因为如果系统突然发生崩溃(电源故障)则内存中的数据会丢失。
2) 将内存中的数据刷新到磁盘
同步脏数据缓冲的过程被称为 刷新 。在Linux 2.6.32内核之前(Red Hat Enterprise Linux 5),通过内核线程pdflush将脏页数据刷新到磁盘。在Linux 2.6.32内核中(Red Hat Enterprise Linux 6.x)pdflush被Per-BDI flush线程(BDI=Backing Device Interface)取代,Per-BDI flush线程以flush-MAJOR:MINOR的形式出现在进程列表中。当内存中脏页比例超过阀值时,就会发生刷新(flush)。
块层处理所有与块设备操作相关的活动。块层中的关键数据结构是bio(block input output)结构,bio结构是在虚拟文件系统层和块层之间的一个接口。
当执行写的时候,虚拟文件系统层试图写入由块缓冲区构成的页缓存,将连续的块放置在一起构成bio结构,然后将其发送到块层。
块层处理bio请求,并链接这些请求进入一个被称为I/O请求的队列。这个链接的操作被称为 I/O电梯调度(I/O elevator)。问个问题:为啥叫电梯调度呢?
Linux 2.4内核使用的是一种单一的通用I/O电梯调度方法,2.6内核提供4种电梯调度算法供用户自己选择。因为Linux操作系统适用的场合很广泛,所以I/O设备和工作负载特性都会有明显的变化。
1)CFQ(Complete Fair Queuing,完全公平队列)
CFQ电梯调度为每个进程维护一个I/O队列,从而 对进程实现一个QoS(服务质量)策略 。CFQ电梯调度能够很好地适应存在很多竞争进程的大型多用户系统。它积极地避免进程饿死并具有低延迟特征。从2.6.18内核发行版开始,CFQ电梯调度成为默认I/O调度器。
CFQ为每个进程/线程单独创建一个队列来管理产生的请求,各队列之间用时间片来调度,以保证每个进程都能分配到合适的I/O带宽。I/O调度器每次执行一个进程的4个请求。
2)Deadline
Deadline是一种循环的电梯调度(round robin)方法,Deadline 算法实现了一个近似于实时的I/O子系统。在保持良好的磁盘吞吐量的同时,Deadline电梯调度既提供了出色的块设备扇区的顺序访问,又确保一个进程不会在队列中等待太久导致饿死。
Deadline调度器为了兼顾这两个方面,引入了4个队列,这4个队列可分为两类,每一类都由读和写两种队列组成。一类队列用来对 请求 按 起始扇区序号 进行排序(通过红黑树来组织),称为sort_list;另一类对 请求 按 生成时间进行排序 (由链表来组织),称为fifo_list。每当确定了一个传输方向(读或写),系统都将会从相应的sort_list中将一批连续请求调度到请求队列里,具体的数目由fifo_batch来确定。 只有遇到三种情况才会导致一次批量传输的结束 :1.对应的sort_list中已经没有请求了;2.下一个请求的扇区不满足递增的要求;3.上一个请求已经是批量传输的最后一个请求了。
所有的请求在生成时都会被赋上一个期限值,并且按期限值将它们排序在fifo_list中, 读请求的期限时长默认为500ms,写请求的期限时长默认为5s。 在Deadline调度器定义了一个writes_starved默认值为2,写请求的饥饿线。 内核总是优先处理读请求,当饿死进程的次数超过了writes_starved后,才会去考虑写请求 。 为什么内核会偏袒读请求呢? 这是从整体性能上进行考虑的。读请求和应用程序的关系是同步的,因为应用程序要等待读取完毕,方能进行下一步工作所以读请求会阻塞进程,而写请求则不一样。应用程序发出写请求后,内存的内容何时被写入块设备对程序的影响并不大,所以调度器会优先处理读请求。
3) NOOP
一个简单的FIFO 队列,不执行任何数据排序。NOOP 算法简单地合并相邻的数据请求,所以增加了少量的到磁盘I/O的处理器开销。NOOP电梯调度假设一个块设备拥有它自己的电梯算法。当后台存储设备能重新排序和合并请求,并能更好地了解真实的磁盘布局时,通常选择NOOP调度,
4)Anticipatory
Anticipatory本质上与Deadline一样,但Anticipatory电梯调度在处理最后一个请求之后会等待一段很短的时间,约6ms(可调整antic_expire改变该值),如果在此期间产生了新的I/O请求,它会在每个6ms中插入新的I/O操作,这样可以将一些小的I/O请求合并成一个大的I/O请求,从而用I/O延时换取最大的I/O吞吐量。
Linux内核使用设备驱动程序得到设备的控制权。 设备驱动程序 通常是一个独立的内核模块,通常针对每个设备(或是设备组)而提供,以便这些设备在Linux操作系统上可用。一旦加载了设备驱动程序,将被当作Linux内核的一部分运行,并能控制设备的运行。
SCSI (Small Computer System Interface,小型计算机系统接口)是最常使用的I/O设备技术,尤其在企业级服务器环境中。SCSI在 Linux 内核中实现,可通过设备驱动模块来控制SCSI设备。 SCSI包括以下模块类型 :
1) Upper IeveI drivers(上层驱动程序)。 sd_mod、sr_mod(SCSI-CDROM)、st(SCSI Tape)和sq(SCSI通用设备)等。
2) MiddIe IeveI driver(中层驱动程序) 。如scsi_mod实现了 SCSI 协议和通用SCSI功能。
3) Low IeveI drivers(底层驱动程序) 。提供对每个设备的较低级别访问。底层驱动程序基本上是特定于某一个硬件设备的,可提供给某个设备。
4) Pseudo drive(伪驱动程序) 。如ide-scsi,用于 IDE-SCSI仿真。
通常一个较大的性能影响是文件系统元数据怎样在磁盘上存放 。引入 磁盘条带阵列 (RAID 0、RAID 5和RAID 6)解决这个问题。在一个条带阵列上,磁头在移动到阵列中下一个磁盘之前,单个磁盘上写入的数据称为 CHUNKSIZE ,所有磁盘使用一次它后返回到第一个磁盘。 如果文件系统的布局没有匹配RAID的设计,则有可能会发生一个文件系统元数据块被分散到2个磁盘上,导致对2个磁盘发起请求 。或者 将所有的元数据在一个单独的磁盘上存储,如果该磁盘发生故障则可能导致该磁盘变成热点 。
设计RAID阵列需要考虑以下内容:
1) 文件系统使用的块大小。
2) RAID 阵列使用的CHUNK大小。
3) RAID 阵列中同等磁盘的数量。
块大小 指可以读取/写入到驱动器的最小数据量,对服务器的性能有直接的影响。块的大小由文件系统决定,在联机状态下不能更改,只有重新格式化才能修改。可以使用的块大小有1024B、2048B、4096B,默认为 4096 B。
stride条带 是在一个chunk中文件系统块的数量。如果文件系统块大小为4KB,则chunk大小为64KB,那么stride是64KB/4KB=16块。
stripe-width 是RAID阵列上一个条带中文件系统块的数量。比如 一个3块磁盘的RAID5阵列 。按照定义,在RAID5阵列每个条带中有1个磁盘包含奇偶校验内容。想要得到stripe-width,首先需要知道每个条带中有多少磁盘实际携带了数据块,即3磁盘-1校验磁盘=2数据磁盘。2个磁盘中的stride是chunk中文件系统块的数量。因此能计算 2(磁盘)*16(stride)=32(stripe)。
创建文件系统时可以使用mkfs给定数量:mk2fs -t ext4 -b 4096 -E stripe=16,stripe_width=64 /dev/vda
3、详解Linux系统内存知识及调优方案
内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。内存作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来,内存的运行也决定了计算机的稳定运行。对于整个操作系统来说,内存可能是最麻烦的的设备。而其性能的好坏直接影响着整个操作系统。
我们知道CPU是不能与硬盘打交道的,只有数据被载入到内存中才可以被CPU调用。cpu在访问内存的时候需要先像内存监控程序请求,由监控程序控制和分配内存的读写请求,这个监控程序叫做MMU(内存管理单元)。下面以32位系统来说明内存的访问过程:
32位的系统上每一个进程在访问内存的时候,每一个进程都当做自己有4个G的内存空间可用,这叫虚拟内存(地址),虚拟内存转化成物理内存是通过MMU来完成的。为了能够从线性地址转换成物理地址,需要page table(页表)的内存空间,page table要载入到MMU上。为了完成线性地址到物理地址的映射,如果按照1个字节1个字节映射的话,需要一张非常大的表,这种转换关系会非常的复杂。因此把内存空间又划分成了另外一种存储单元格式,通常为4K。在不同的硬件平台上,它们的大小一般是不一样的,像x86 32位的有4k的页;而64位的有4k页,2M页,4M页,8M页等等,默认都是4k的。每一个进程一般而言都有自己的页路径和页表映射机制,不管那一个页表都是由内核加载的。每一个进程只能看到自己的线性地址空间,想要增加新的内存的时候,只能在自己的线性地址空间中申请,并且申请后一定是通过操作系统的内核映射到物理地址空间中去找那么一段空间,并且告诉线性地址空间准备好了,可以访问,并且在page table中增加一条映射关系,于是就可以访问物理内存了,这种叫做内存分配。但是新的申请一定是通过操作的内核到物理内存中去找那么一段空间,并且告诉线性地址空间好了,可以建设映射关系,最终page table建立映射关系。
这反映了上述描述过程的大体情况。可以看到每一个用户程序都会有自己的页表,并且映射到对应的主存储器上去。
根据上述文字和图表的描述可以发现2个问题:
1.每个进程如果需要访问内存的时候都需要去查找page table的话,势必会造成服务器的性能底下
2.如果主存储器的内存满了以后,应用程序还需要调用内存的时候怎么办
对于第一个问题,我们就需要借助TLB(Translation Lookaside Buffer)翻译后备缓冲器。TLB是一个内存管理单元,它可以用于改进虚拟地址到物理地址转换速度的缓存。这样每次在查找page table的时候就可以先去TLB中查找相应的页表数据,如果有就直接返回,没有再去查找page table,并把查找到的结果缓存中TLB中。TLB虽然解决了缓存的功能,但是在那么page table中查找映射关系仍然很慢,所以又有了page table的分级目录。page table可以分为1级目录,2级目录和偏移量
但是一个进程在运行的时候要频繁的打开文件,关闭文件。这就意味着要频繁的申请内存和释放内存。有些能够在内存中缓存数据的那些进程,他们对内存的分配和回收更多,那么每一次分配都会在页表中建立一个对应项。所以,就算内存的速度很快,大量频繁的同一时间分配和释放内存,依然会降低服务器的整体性能。当然内存空间不够用的时候,我们称为oom(out of memory,内存耗尽)。当内存耗尽的时候,,整个操作系统挂了。这种情况下我们可以考虑交换分区,交换分区毕竟是由硬盘虚拟出来的内存,所以其性能与真正的内存相比,差了很多,所以要尽力避免使用交换分区。有物理内存空间的时候尽量保证全部使用物理内存。cpu无论如何是不能给交换内存打交道的,它也只能给物理内存打交道,能寻址的空间也只能是物理内存。所以当真正物理内存空间不够用的时候,会通过LRU算法把其中最近最少使用的内存放到交换内存中去,这样物理内存中的那段空间就可以供新的程序使用了。但是这样会引发另外的一个问题,即原来的进程通过page table寻找的时候,那一段空间的数据已经不属于它了。所以此刻cpu发送通知或者异常告诉这个程序,这个地址空间已不属于它,这个时候可能会出现2种情况:
1.物理内存有可用的空间可用:这个时候cpu会根据以前的转换策略会把交换分区中的那段内存重新送到物理内存中去,但是转换过来的空间地址不一定会是以前的那一段空间地址,因为以前的那一段空间地址可能已经被别人使用了。
2.物理内存没有可用的空间可用:这个时候依然会使用LRU算发把当前物理地址空间上最近最少使用的空间地址转换到交换内存中去,并把当前进程需要的这断在交换空间中的内存送到物理内存空间中去,并且重新建立映射关系。
上述通知或者异常出现的情况,通常叫做缺页异常。缺页异常也分为大异常和小异常两种。大异常就是访问的数据内存中没有,不的不去硬盘上加载,无论是从交换内存中还是直接从磁盘的某个文件系统上,反正需要从硬盘上去加载,这种异常加载需要很长时间。小异常就是进程之间通过共享内存,第二个进程访问的时候,查看本地的内存映射表没有,但是其它进程已经拥有了这个内存页,所以可以直接映射,这种异常加载需要的时间一般很短。
在操作系统开机的时候,每一个io设备都会像cpu申请一些列的随机端口,这种端口叫做io端口。在IBM PC体系结构中,I/O地址空间一共提供了65,536个8位的I/O端口。正是这些io端口的存在,cpu可以与io设备进行读写交互的过程。在执行读写操作时,CPU使用地址总线选择所请求的I/O端口,使用数据总线在CPU寄存器和端口之间传送数据。I/O端口还可以被映射到物理地址空间:因此,处理器和I/O设备之间的通信就可以直接使用对内存进行操作的汇编语言指令(例如,mov、and、or等等)。现代的硬件设备更倾向于映射I/O,因为这样处理的速度较快,并可以和DMA结合起来使用。这样io在和内存传数据的时候就不需要通过cpu,cpu把总线的控制权交给DMA,每次io传数据的时候就调用DMA一次,就把cpu给解放了出来。当数据传输完了以后,DMA通知给cpu中断一次。DMA在运行的时候对整个总线有控制权限,当cpu发现有其它进程需要使用总线的时候,二者就会产生争用。这个时候,在总线控制权的使用上,CPU和DMA具有相等的权限。只要CPU委托给了DMA,就不能随意的收回这个委托,就要等待DMA的用完。
如果没有其它进程可以运行,或者其它进程运行的时间非常短,这个时候CPU发现我们的IO仍然没有完成,那就意味着,CPU只能等待IO了。CPU在时间分配里面有个iowait的值,就是CPU在等待IO花费的时间。有些是在同步调用过程中,CPU必须要等待IO的完成;否者CPU可以释放IO的传输在背后自动完成,CPU自己去处理其它的事情。等硬盘数据传输完成以后,硬盘只需要像CPU发起一个通知即可。CPU外围有一种设备,这个设备叫做可编程中断控制器。每一个硬件设备为了给CPU通信,在刚开机的时候,在BIOS实现检测的时候,这个设备就要到可编程中断控制器上去注册一个所谓的中断号。那么这个号码就归这个硬件使用了。当前主机上可能有多个硬件,每一个硬件都有自己的号码,CPU在收到中断号以后,就能够通过中断相量表查找到那个硬件设备进行中断。并且就由对应的IO端口过来处理了。
CPU正在运行其它进程,当一个中断请求发过来的时候,CPU会立即终止当前正在处理的进程,而去处理中断。当前CPU挂起当前正在处理的进程,转而去执行中断的过程,也叫做中断切换。只不过,这种切换在量级别上比进程切换要低一些,而且任何中断的优先级通常比任何进程也要高,因为我们指的是硬件中断。中断还分为上半部和下半部,一般而言,上半部就是CPU在处理的时候,把它接进来,放到内存中,如果这个事情不是特别紧急(CPU或者内核会自己判断),因此在这种情况下,CPU回到现场继续执行刚才挂起的进程,当这个进程处理完了,再回过头来执行中断的下半部分。
在32位系统中,我们的内存(线性地址)地址空间中,一般而言,低地址空间有一个G是给内核使用的,上面3个G是给进程使用的。但是应该明白,其实在内核内存当中,再往下,不是直接这样划分的。32位系统和64位系统可能不一样(物理地址),在32位系统中,最低端有那么10多M的空间是给DMA使用的。DNA的总线宽度是很小的,可能只有几位,所以寻址能力很有限,访问的内存空间也就很有限。如果DMA需要复制数据,而且自己能够寻址物理内存,还可以把数据直接壮哉进内存中去,那么就必须保证DMA能够寻址那段内存才行。寻址的前提就是把最低地址断M,DA的寻址范围内的那一段给了DMA。所以站在这个角度来说,我们的内存管理是分区域的。
在32位系统上,16M的内存空间给了ZONE_DMA(DMA使用的物理地址空间);从16M到896M给了ZONE_NORMAL(正常物理地址空间),对于Linux操作系统来说,是内核可以直接访问的地址空间;从896M到1G这断空间叫做"Reserved"(预留的物理地址空间);从1G到4G的这段物理地址空间中,我们的内核是不能直接访问的,要想访问必须把其中的一段内容映射到Reserved来,在Reserved中保留出那一段内存的地址编码,我们内核才能上去访问,所以内核不直接访问大于1G的物理地址空间。所以在32位系统上,它访问内存当中的数据,中间是需要一个额外步骤的。
在64位系统上,ZONE_DAM给了低端的1G地址空间,这个时候DMA的寻址能力被大大加强了;ZONE_DAM32可以使用4G的空间;而大于1G以上给划分了ZONE_NORMAL,这段空间都可以被内核直接访问。所以在64位上,内核访问大于1G的内存地址,就不需要额外的步骤了,效率和性能上也大大增加,这也就是为什么要使用64位系统的原因。
在现在的PC架构上,AMD,INTER都支持一种机制,叫做PEA(物理地址扩展)。所谓PAE。指的是在32位系统的地址总线上,又扩展了4位,使得32位系统上的地址空间可以达到64G。当然在32为系统上,不管你的物理内存有多大,单个进程所使用的空间是无法扩展的。因为在32位的系统上,线性地址空间只有4个G,而单个进程能够识别的访问也只有3个G。
linux的虚拟内存子系统包含了以下几个功能模块:
slab allocator,zoned buddy allocator,MMU,kswapd,bdflush
slab allocator叫做slab分配器
buddy allocator又叫做buddy system,叫做伙伴系统,也是一种内存分配器
buddy system是工作在MMU之上的,而slab allocator又是工作在buddy system之上的。
设置为小于等于1G,在数据库服务器应该劲量避免使用交换内存
3.在应用服务器上,可以设置为RAM*0.5,当然这个是理论值
如果不的不使用交换内存,应该把交换内存放到最靠外的磁道分区上,因为最外边的磁盘的访问速度最快。所以如果有多块硬盘,可以把每块硬盘的最外层的磁道拿一小部分出来作为交换分区。交换分区可以定义优先级,因此把这些硬盘的交换内存的优先级设置为一样,可以实现负载均衡的效果。定义交换分区优先级的方法为编辑/etc/fstab:
/dev/sda1 swap swap pri=5 0 0
/dev/sdb1 swap swap pri=5 0 0
/dev/sdc1 swap swap pri=5 0 0
/dev/sdd1 swap swap pri=5 0 0
四.内存耗尽时候的相关调优参数
当Linux内存耗尽的时候,它会杀死那些占用内存最多的进程,以下三种情况会杀死进程:
1.所有的进程都是活动进程,这个时候想交换出去都没有空闲的进程
2.没有可用的page页在ZONE_NORMAL中
3.有其它新进程启动,申请内存空间的时候,要找一个空闲内存给做映射,但是这个时候找不到了
一旦内存耗尽的时候,操作系统就会启用oom-kill机制。
在/proc/PID/目录下有一个文件叫做oom_score,就是用来指定oom的评分的,就是坏蛋指数。
如果要手动启用oom-kill机制的话,只需要执行echo f/proc/sysrq-trigger即可,它会自动杀掉我们指定的坏蛋指数评分最高的那个进程
可以通过echo n /proc/PID/oom_adj来调整一个进程的坏蛋评分指数。最终的评分指数就是2的oom_adj的值的N次方。假如我们的一个进程的oom_adj的值是5,那么它的坏蛋评分指数就是2的5次方。
如果想禁止oom-kill功能的使用可以使用vm.panic_on_oom=1即可。
五.与容量有关的内存调优参数:
overcommit_memory,可用参数有3个,规定是否能够过量使用内存:
0:默认设置,内核执行启发式的过量使用处理
1:内核执行无内存的过量使用处理。使用这个值会增大内存超载的可能性
2:内存的使用量等于swap的大小+RAM*overcommit_ratio的值。如果希望减小内存的过度使用,这个值是最安全的
overcommit_ratio:将overcommit_memory指定为2时候,提供的物理RAM比例,默认为50
六.与通信相关的调优参数
常见在同一个主机中进行进程间通信的方式:
1.通过消息message;2.通过signal信号量进行通信;3.通过共享内存进行通信,跨主机常见的通信方式是rpc
以消息的方式实现进程通信的调优方案:
msgmax:以字节为单位规定消息队列中任意消息的最大允许大小。这个值一定不能超过该队列的大小(msgmnb),默认值为65536
msgmnb:以字节为单位规定单一消息队列的最大值(最大长度)。默认为65536字节
msgmni:规定消息队列识别符的最大数量(及队列的最大数量)。64位架构机器的默认值为1985;32位架构机器的默认值为1736
以共享内存方式实现进程通信的调优方案:
shmall:以字节为单位规定一次在该系统中可以使用的共享内存总量(单次申请的上限)
shmmax:以字节为单位规定每一个共享内存片段的最大大小
shmmni:规定系统范围内最大共享内存片段。在64和32位的系统上默认值都是4096
七.与容量相关的文件系统可调优参数:
file-max:列出内核分配的文件句柄的最大值
dirty_ratio:规定百分比值,当脏数据达到系统内存总数的这个百分比值后开始执行pdflush,默认为20
dirty_background_ratio:规定百分比值,当某一个进程自己所占用的脏页比例达到系统内存总数的这个百分比值后开始在后台执行pdflush,默认为10
dirty_expire_centisecs:pdlush每隔百分之一秒的时间开启起来刷新脏页,默认值为3000,所以每隔30秒起来开始刷新脏页
dirty_writeback_centisecs:每隔百分之一秒开始刷新单个脏页。默认值为500,所以一个脏页的存在时间达到了5秒,就开始刷新脏
八.linux内存常用的观察指标命令:
Memory activity
vmstat [interval] [count]
sar -r [interval] [count]
Rate of change in memory
sar -R [interval] [count]
frmpg/s:每秒释放或者分配的内存页,如果为正数,则为释放的内存页;如果为负数,则为分配的内存页
bufpg/s:每秒buffer中获得或者释放的内存页。如果为正数则为获得的内存页,为负数。则为释放的内存页
campg/s:每秒cache中获得或者释放的内存页。如果为正数则为获得的内存页,为负数。则为释放的内存页
Swap activity
sar -W [interval] [count]
ALL IO
sar -B [interval] [count]
pgpgin/s:每秒从磁盘写入到内核的块数量
pgpgout/s:每秒从内核写入到磁盘的块数量
fault/s:每秒钟出现的缺页异常的个数
majflt/s:每秒钟出现的大页异常的个数
pgfree/s:每秒回收回来的页面个数
4、vss pss rss 哪个用来内存消耗
RSS列表示,程序占用了多少物理内存。
虚拟内存可以不用考虑,它并不占用实际物理内存。
(2)。
top命令也可以其中VIRT(或VSS)列表示,程序占用了多少虚拟内存。
同psaux中的VSZ列RES列表示,程序占用了多少物理内存。
同psaux中的RSS列2.在linux下,查看当前系统占用了多少内存,一般的命令是free其中,free就是系统还有多少内存可以使用。
但由于linux系统对内存使用有一个原则,就是,内存是宝贵的,能使用多少就使用多少。
所以,linux会把已经调用过的包缓存起来,放在内存里。
这样,实际上,可以使用的内存,就可以理解为,free+buffers+cached3.当了解完这些命令以后,再去使用psaux命令去查看的时候,会发现一个奇怪的现象。
所有的RSS列的数据,加起来,比物理内存的数要大很多。
比如,物理内存为2G,而RSS列的数据加起来,可能有5个G之多,这是怎么回事了?这是因为RSS列的值骗了。
linux的内存机制是这样的:在运行一个程序时,linux会调用该程序依赖的链接库,如lib.xx.so。
首先看该链接库是否被映射进内存中,如果没有被映射,则将代码段与数据段映射到内存中,否则只是将其加入进程的地址空间。
这样,当N个程序,依赖到lib.xx.so的时候,实际上,内存中只有一个lib.xx.so,而不是N个。
而RSS在显示一个程序占用的实际物理内存时,将lib.xx.so也算了进来。
比如,X程序,本身占用内存为5M,lib.xx.so占用内存2M,lib.xx.so被N个程序共享依赖。
则RSS显示为,X程序运行,占用内存为7M。
实际上,X程序占用了5M空间。
多余的2m被讨入到RSS中了。
当在用psaux显示内存占用情况时,N个共享依赖lib.xx.so的N个程序,都把这2m空间,算在自己的RSS中了,这样RSS的sum值,就比实际物理内存多了。
当然,linux的内存使用机制很复杂,不是一句两句能说清楚的。
这里只是简单的说明了一下,psaux中的RSS值,并不能真实反映物理内存的使用情况。
4.如果查看更详细的内存使用情况,可用以下几种方法,或者几种方法结合使用:这几种方法,都需要root账户的权限(1)。
pmap-d$pid$pid是正在运行的程序的pid(2)。
cat/proc/$pid/smapssmaps的数据比较详细,可简单的归纳一下,归纳的命令如下:cat/proc/$pid/smaps|awk'/Size|Rss|Pss|Shared|Private|Referenced|Swap/{val_name=gensub(/([a-zA-Z_]*)。
*/,“\\1”,1,$1);list[val_name]+=$2;}END{for(valinlist)printval,list[val];}‘(3)。
cat/proc/$pid/maps(4)。
cat/proc/$pid/statm输出解释第一列size:任务虚拟地址空间大小
第二列Resident:正在使用的物理内存大小
第三列Shared:共享页数
第四列Trs:程序所拥有的可执行虚拟内存大小
第五列Lrs:被映像倒任务的虚拟内存空间的库的大小
第六列Drs:程序数据段和用户态的栈的大小
第七列dt:脏页数量(5)。
vmstat这个命令据说也可以提供一些参考信息,具体还未研究5.作为phper,尝试过使用php的函数memory_get_usage(),该函数也不能得到php当前运行的程序,实际的,真正占用的内存数量。
如果真想得到,php真正占用的内存,大概只能在,程序运行的开始,执行一次memory_get_usage()。
在程序运行结束,执行一次memory_get_usage()。
将两者的值相减,得到的值,应该是一个相对比较准确的,内存占用数量了。
这个方法还没有测试,考虑到,得到这个数量,也没有实际意义,加上平时又比较忙,懒得试了。
5、Swap 机制
当发生了内存泄漏时,或者运行了大内存的应用程序,导致系统的内存资源紧张时,系统又会如何应对呢?
这其实会导致两种可能结果,内存回收和 OOM 杀死进程。
我们先来看后一个可能结果,内存资源紧张导致的 OOM(Out Of Memory),相对容易理解,指的是系统杀死占用大量内存的进程,释放这些内存,再分配给其他更需要的进程。
接下来再看第一个可能的结果,内存回收,也就是系统释放掉可以回收的内存,比如我前面讲过的缓存和缓冲区,就属于可回收内存。它们在内存管理中,通常被叫做文件页(File-backed Page)
大部分文件页,都可以直接回收,以后有需要时,再从磁盘重新读取就可以了。而那些被应用程序修改过,并且暂时还没写入磁盘的数据(也就是脏页),就得先写入磁盘,然后才能进行内存释放。
这些脏页,一般可以通过两种方式写入磁盘。
除了缓存和缓冲区,通过内存映射获取的文件映射页,也是一种常见的文件页。它也可以被释放掉,下次再访问的时候,从文件重新读取。
除了文件页外,还有没有其他的内存可以回收呢?比如,应用程序动态分配的堆内存,也就是我们在内存管理中说到的匿名页(Anonymous Page),是不是也可以回收呢?
我想,你肯定会说,它们很可能还要再次被访问啊,当然不能直接回收了。非常正确,这些内存自然不能直接释放。
但是,如果这些内存在分配后很少被访问,似乎也是一种资源浪费。是不是可以把它们暂时先存在磁盘里,释放内存给其他更需要的进程?
其实,这正是 Linux 的 Swap 机制。Swap 把这些不常访问的内存先写到磁盘中,然后释放这些内存,给其他更需要的进程使用。再次访问这些内存时,重新从磁盘读入内存就可以了。
Swap 说白了就是把一块磁盘空间或者一个本地文件(以下讲解以磁盘为例),当成内存来使用。它包括换出和换入两个过程。
Swap 其实是把系统的可用内存变大了。这样,即使服务器的内存不足,也可以运行大内存的应用程序。
我们常见的笔记本电脑的休眠和快速开机的功能,也基于 Swap 。休眠时,把系统的内存存入磁盘,这样等到再次开机时,只要从磁盘中加载内存就可以。这样就省去了很多应用程序的初始化过程,加快了开机速度。
既然 Swap 是为了回收内存,那么 Linux 到底在什么时候需要回收内存呢?前面一直在说内存资源紧张,又该怎么来衡量内存是不是紧张呢?
一个最容易想到的场景就是,有新的大块内存分配请求,但是剩余内存不足。这个时候系统就需要回收一部分内存(比如前面提到的缓存),进而尽可能地满足新内存请求。这个过程通常被称为 直接内存回收 。
除了直接内存回收,还有一个专门的内核线程用来定期回收内存,也就是kswapd0。为了衡量内存的使用情况,kswapd0 定义了三个内存阈值(watermark,也称为水位),分别是页最小阈值(pages_min)、页低阈值(pages_low)和页高阈值(pages_high)。剩余内存,则使用 pages_free 表示。
这里,我画了一张图表示它们的关系。
kswapd0 定期扫描内存的使用情况,并根据剩余内存落在这三个阈值的空间位置,进行内存的回收操作。
我们可以看到,一旦剩余内存小于页低阈值,就会触发内存的回收。这个页低阈值,其实可以通过内核选项 /proc/sys/vm/min_free_kbytes 来间接设置。min_free_kbytes 设置了页最小阈值,而其他两个阈值,都是根据页最小阈值计算生成的,计算方法如下 :
很多情况下,你明明发现了 Swap 升高,可是在分析系统的内存使用时,却很可能发现,系统剩余内存还多着呢。为什么剩余内存很多的情况下,也会发生 Swap 呢?
看到上面的标题,你应该已经想到了,这正是处理器的 NUMA (Non-Uniform Memory Access)架构导致的。
关于 NUMA,我在 CPU 模块中曾简单提到过。在 NUMA 架构下,多个处理器被划分到不同 Node 上,且每个 Node 都拥有自己的本地内存空间。
而同一个 Node 内部的内存空间,实际上又可以进一步分为不同的内存域(Zone),比如直接内存访问区(DMA)、普通内存区(NORMAL)、伪内存区(MOVABLE)等,如下图所示
先不用特别关注这些内存域的具体含义,我们只要会查看阈值的配置,以及缓存、匿名页的实际使用情况就够了。
既然 NUMA 架构下的每个 Node 都有自己的本地内存空间,那么,在分析内存的使用时,我们也应该针对每个 Node 单独分析。
你可以通过 numactl 命令,来查看处理器在 Node 的分布情况,以及每个 Node 的内存使用情况。比如,下面就是一个 numactl 输出的示例:
这个界面显示,我的系统中只有一个 Node,也就是 Node 0 ,而且编号为 0 和 1 的两个 CPU, 都位于 Node 0 上。另外,Node 0 的内存大小为 7977 MB,剩余内存为 4416 MB。
了解了 NUNA 的架构和 NUMA 内存的查看方法后,你可能就要问了这跟 Swap 有什么关系呢?
实际上,前面提到的三个内存阈值(页最小阈值、页低阈值和页高阈值),都可以通过内存域在 proc 文件系统中的接口 /proc/zoneinfo 来查看。
比如,下面就是一个 /proc/zoneinfo 文件的内容示例:
这个输出中有大量指标,我来解释一下比较重要的几个。
从这个输出结果可以发现,剩余内存远大于页高阈值,所以此时的 kswapd0 不会回收内存。
当然,某个 Node 内存不足时,系统可以从其他 Node 寻找空闲内存,也可以从本地内存中回收内存。具体选哪种模式,你可以通过 /proc/sys/vm/zone_reclaim_mode 来调整。它支持以下几个选项:
到这里,我们就可以理解内存回收的机制了。这些回收的内存既包括了文件页,又包括了匿名页。
不过,你可能还有一个问题。既然有两种不同的内存回收机制,那么在实际回收内存时,到底该先回收哪一种呢?
其实,Linux 提供了一个 /proc/sys/vm/swappiness 选项,用来调整使用 Swap 的积极程度。
swappiness 的范围是 0-100,数值越大,越积极使用 Swap,也就是更倾向于回收匿名页;数值越小,越消极使用 Swap,也就是更倾向于回收文件页。
虽然 swappiness 的范围是 0-100,不过要注意,这并不是内存的百分比,而是调整 Swap 积极程度的权重,即使你把它设置成 0,当剩余内存 + 文件页小于页高阈值时,还是会发生 Swap。
在内存资源紧张时,Linux 通过直接内存回收和定期扫描的方式,来释放文件页和匿名页,以便把内存分配给更需要的进程使用。
你可以设置 /proc/sys/vm/min_free_kbytes,来调整系统定期回收内存的阈值(也就是页低阈值),还可以设置 /proc/sys/vm/swappiness,来调整文件页和匿名页的回收倾向。
在 NUMA 架构下,每个 Node 都有自己的本地内存空间,而当本地内存不足时,默认既可以从其他 Node 寻找空闲内存,也可以从本地内存回收。
你可以设置 /proc/sys/vm/zone_reclaim_mode ,来调整 NUMA 本地内存的回收策略。
关于linux脏页有多少个和linux 脏页的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。