
009-Linux内核
文章平均质量分 77
Linux内核
牛不才
c/c++ linux 后端 架构 搜索引擎
展开
-
Linux中的IO体系结构
Linux内核一个的主要作用就是管理硬件,而像键盘、鼠标、显示器、网卡、硬盘、打印机、CD/DVD等等这么多设备,形状、用法、处理速度、功能都不一样,该怎么统一管理起来呢?1. 一切皆文件在linux中一切皆文件,设备也不例外,设备文件放在dev目录下。应用程序可以像访问普通文件一样访问设备,内核vfs下面的驱动程序层和硬件实现具体的功能。ubuntu@VM-0-16-ubuntu:~$ ls -l /dev/total 0crw-r--r-- 1 root root原创 2021-05-20 01:05:17 · 548 阅读 · 0 评论 -
Linux 巨型页(HugePages)
1. 什么是巨型页页面是Linux管理内存的基本单位,一般为4KB。如果程序运行时,需要大量的内存,就会产生非常多的TLB未命中和缺页异常,4KB的尺寸显然称为程序的瓶颈。如果直接修改系统默认页面大小,那么系统中其他程序运行时,很可能又会造成内存浪费。所以,Linux引入了巨型页,这种巨型页允许管理远大于4k的大页面,默认是2M,相当于512个普通页面。简而言之,通过启用大页面,系统可以处理更少的页面表,因此访问/维护它们的开销也更少!巨型页的应用集中在对内存需求大的领域,比如数据库、虚拟机等系统中原创 2021-05-05 19:59:54 · 3356 阅读 · 0 评论 -
物理内存组织结构
内存管理在内核中占据着举足轻重的地位,毕竟它是用来处理处理器和内存之间的协作的,而后两者都是计算机中最为重要的资源。内存管理的目标就是高效合理的使用物理内存,不造成浪费。1. 体系结构在计算机发展初期,如上图,CPU通过总线访问整个地址空间,这是一种简单经济的方式,可以尽可能使用内存。但是这个系统本身也存在伸缩性的问题,因为总线的宽度是有限的,这也限制了处理器的数量。如果添加CPU,会引起以下两个问题CPU增加,每个节点的可用带宽会减少 CPU增加,总线长度会增加,进而增加了延迟于.原创 2021-05-04 15:44:13 · 1577 阅读 · 2 评论 -
反碎片技术和虚拟可移动区域
Linux在内存管理上,存在一个问题,那就是在系统运行很长一段时间后,物理内存中的碎片会越来越多。1. 内存碎片整理1.1 什么是内存碎片呢?内存碎片分为两种,一种是内存页中的碎片,被称为内部碎片;另一种是空闲分散的内存页,凑不齐一个组物理地址连续的空闲内存页,就没办法分配了,这些散落的内存页被称为外部碎片。1.2 内核引入的反碎片技术2.6.23 引入成块回收,3.5版本后废除,被碎片整理程序取而代之 2.6.33 引入虚拟可移动区域其中,不管是成块回收还是碎片整理,它们.原创 2021-05-03 23:35:00 · 1220 阅读 · 8 评论 -
进程
1. 什么是进程在 《面对多任务处理、程序员是怎样榨干计算机资源的》提到,不管是进程、线程、协程都是用来处理用户任务的。从内核角度来看,进程就是用来分配CPU、内存等资源的。后来觉得进程分配CPU时间片太重了,于是轻量级进程、线程就出现了,成了CPU调度的基本单位,但是资源分配的基本单位还是进程。通俗的讲,进程被定义为程序运行的一个实例。为了管理进程,内核引入了一个进程描述符的数据结构。2. 进程的生命周期(状态)进程描述符中的state字段描述了进程所处的状态。粗略的看,进程要...原创 2021-05-03 21:07:09 · 183 阅读 · 0 评论 -
页表
1. 虚拟和物理地址空间每个进程的内存地址空间在大多数情况下要比系统中可用的物理内存要大。内核要考虑将实际内存划分给进程需要的地址空间,最可取的一个方法就是加一个页表。页表来为物理地址分配虚拟地址,进程的地址空间则用虚拟地址表示。如下图所示,不同进程的同一个虚拟地址可能会映射到同一个物理内存页(通常称为页帧)上,它们的含义是不同的。2. 页表页表的作用就是将虚拟地址空间映射到物理地址空间。那么最容易让人想到的办法就是使用一个数组,但在实际应用中最普遍的是多级分页。2.1 数组页表.原创 2021-05-03 11:12:08 · 2538 阅读 · 0 评论 -
指令重排和优化屏障
1. 优化带来的烦恼用过GCC编译的同学应该知道GCC有O0、O1、O2、O3等优化选项,启用这些选项往往可以提高程序的运行效率,但它并不是万无一失的,尤其是在多线程场景下。而这些优化背后的技术正是指令重排。因为编译器或处理器也很难确定代码逻辑的原本意图。锁能够保持原子性,但是经过编译器优化之后的代码,并不是绝对时序正确的,况且处理器还有可能进一步优化。这里面最经典的一个例子就是单例模式,Double-Checked Locking is Fixed In C++11 。2. 内核提供的解决方案原创 2021-04-30 19:14:44 · 918 阅读 · 3 评论 -
RCU
1. 什么是RCURCU(Read-Copy-Update),是一种同步机制,它虽然对内存有一定的开销,但是它的性能非常好。在Linux内核中随处可见它的身影。2. RCU的工作机制RCU下,会记录指向共享结构体指针的所用使用者。这个结构体将要被修改时,首相将会创建一个副本,然后把改动写入副本当中。当所有的读操作使用者访问结束之后,指针指向新的修改后副本的指针,副本就这么上位了,修改也就是最新的了。基本原理是很简单的,一个备胎而已,空闲时上位而已。要是支持多任务读写并发,就复杂些了。3. 适原创 2021-04-30 19:09:09 · 1316 阅读 · 1 评论 -
eventfd
1. 简介eventfd - create a file descriptor for event notificationeventfd是通过事件通知机制。int eventfd(unsigned int initval, int flags);eventfd创建一个“eventfd对象”,可以用作事件等待/通知机制由用户空间应用程序和通知用户空间应用程序事件的内核。这个对象包含由内核维护的无符号64位整数计数器。此计数器已初始化使用参数initval中指定的值。eventfd()返回一原创 2021-04-27 19:49:06 · 1921 阅读 · 0 评论 -
内核模块
Linux模块概述Linux内核是宏内核,除了基本功能之外,文件系统和驱动程序都集成在一起管理,这样做呢,相对于微内核而言少了很多切换的消耗,效率很高,但是扩展性和可维护性就较差了,为了弥补这一不足,就诞生了模块机制。模块可以在内核启动的过程中加载,也就是所说的静态加载,也可以在运行过程中加载,动态加载和卸载,不需要重新编译内核,扩展和维护性就提高了。一个模块加载到内核中之后,就成了内核的一...原创 2020-03-24 10:43:50 · 221 阅读 · 0 评论 -
进程间通信 IPC 概述
Linux进程间通信,大致有五种原始的信号和管道,还有共享内存,消息队列和信号。1. 管道管道分为两种 pipe和fifopipe可用有亲缘关系的进程,比如父子进程,兄弟进程fifo可用不同进程之间,不限于亲缘关系pipe半双工,一端读一端写,数据在一个方向上流动。可以看成是一种特殊的文件,只不过它只在内存里,不落地到文件系统。管道的缓冲区有限制,PIPE_BUF 一般是一个页面的...原创 2020-03-24 09:47:20 · 196 阅读 · 0 评论 -
TCP如何进行拥塞控制
拥塞控制和流量控制不一样,后者是端对端的问题,它则是一个全局的问题,涉及主机,路由器等等通信设备,还有些和降低传输性能有关的问题。主要涉及三个算法慢开始算法如图所示,拥塞窗口cwnd在最开始时,值为1,然后按照*2翻倍的形式增长直到这个值大于等于 慢开始门限之后,从这个门限16开始,以+1的形式增长直到发生超时,那么cwnd变为1,再按照*2翻倍的形式增长但是这次慢开始门限变了...原创 2020-03-27 12:12:39 · 1272 阅读 · 0 评论 -
TCP如何进行流量控制
TCP中的流量控制和拥塞控制不同,它只解决端到端之间的问题。往往是要通过降低发送端发送数据的速率,以便接收端能够处理,而不造成拥塞。在TCP的首部,有一个标识窗口大小的16位字段,这个字段越大,说明滑动窗口(缓冲区越大),网络的吞吐量也就越大。接收端在收到ACK请求之后,也会把自己的窗口大小填进去,回应发送端,两端取一个最小的窗口尺寸进行数据发送。如果,接收端这边网络拥堵,状况不佳,那么这个窗...原创 2020-03-27 11:48:37 · 4173 阅读 · 0 评论 -
TCP如何保证可靠性
TCP是基于IP协议的传输层协议,但是IP协议本身是不可靠的,那么就得从TCP上做文章。1.校验和 保证传输数据正确这个校验和和UDP中的校验和基本一致,伪首部+TCP首部+数据 一起计算出校验和,一个16位的整数伪首部组成如下:源IP地址(32位)| 目的IP地址(32位)|填充0(8位)|协议号(8位)|UDP包长度(16位)那么为什么要把这个伪首部加进来呢?TCP/IP通信中有...原创 2020-03-27 11:31:38 · 436 阅读 · 0 评论 -
TCP首部格式
源端口号(16位) 目 的 端 口 号(16位) 序列号(32位) 确认应答号(32位) 偏移 ...原创 2020-03-26 14:30:11 · 459 阅读 · 0 评论 -
UDP首部格式
TCP和UDP首部格式UDP首部格式 源端口号 目标端口号 包长度 校验和 数据部分 源端口号表示发送端端口号,长度16位,可选项,如果不需要返回数据数据,可以不设置。目标端口号表示接收端端口号,长度16位。包长度该字段保存了UDP首部+数据的...原创 2020-03-26 10:26:39 · 1718 阅读 · 0 评论 -
简单定时器
本文基于循环数组实现了一个简单的时间轮定时器。定时器可以出发单次或者循环触发。定时器,每隔一秒往下走一个格子,并扫描数组节点中有无要触发的事件。一个格子中可能有多个节点,触发层级为0的节点。这个例子比较简单,通过alarm系统调用来实现的,alarm会发SIGALRM信号,触发tick函数执行。#include <signal.h>#include <stdio.h>#include <unistd.h>#define TIME_WHEEL_S.原创 2021-01-01 13:33:05 · 439 阅读 · 0 评论 -
文件系统
块常见的文件系统,windows上有FAT32、NTFS等,linux上面有ext2、ext3、ext4、xfs等。当然,linux上也支持ntfs,fat32等。这是从操作系统的层面粗略的讲。另外,fat32常用于U盘、闪卡等介质,现在的U盘等做的越来越好了,所以NTFS的U盘也很常见。我们知道以前的U盘不能存大文件,也就是说超过4GB的文件存不了。为什么呢?因为fast32是32位的文件系统,没有错,文件系统也分32位64位。ext2也是和fat32属于同时期的产品。最大文件4GB等等各种限制,在原创 2020-12-30 23:12:10 · 338 阅读 · 0 评论 -
计算机存储、缓存简介
计算机中存储数据的介质,由快到慢大致有寄存器L1 CacheL2 CacheL3 Cache内存SSD 固态硬盘普通硬盘计算机理论上处理信息的最高速度,是由晶振频率决定的。晶振全程石英振荡器,它的振荡频率稳定。石英表,正是利用这一特性来工作的。用一个我们可能更熟悉的词汇代替晶振频率,那就是时钟信号。如果一个CPU的时钟信号是1GHz,就代表着一个时钟信号的周期是1/(1G),即十亿分之一秒,1纳秒。理想情况下,如果不做存储分级,所有数据都放到CPU里面,那CPU的能耗是非常大的,那原创 2020-12-22 16:52:36 · 1057 阅读 · 0 评论 -
信号驱动io模型简述
1.什么是信号驱动IO?信号驱动IO,预先在内核中设置一个回调函数,当某个事件发生时,内核使用信号(SIGIO)通知进程来处理(运行回调函数)。 它也可以看成是一种异步IO,因为检测fd是否有数据和是否可读写是在两个流程中做的。它的优势是,进程没有收到SIGIO信号之前,不被阻塞,可以做其他事情。它的劣势是,当数据量变大时,信号产生太频繁,性能会非常低。内核需要不断的把数据复制到用户态。2. 参考代码一般信号驱动io用于udp#include <fcntl.h>#include原创 2020-11-15 17:44:50 · 2686 阅读 · 0 评论 -
线程局部存储的三种方式
在某些情况下,我们需要使用线程独有的变量,其他线程不干扰。实现的方式主要有以下三种,一是gcc提供的_thread, 二是pthread提供的pthread_key_t ,三则是c++11提供的thread_local。无论那种方式,它们都能保证变量只对当前线程可见。1. gcc中的_thread_thread 修饰线程周期的变量,主要用法有 __thread int i; extern __thread struct state s; static __t.原创 2021-04-22 21:45:12 · 873 阅读 · 0 评论 -
面对多任务处理、程序员是怎样榨干计算机资源的
你是否经常遇到这样的问题?“进程和线程有什么区别?请简述下对协程的认识?”等等。当然这些问题可谓是老生常谈。但是我想,如果我们从计算机发展史的角度,回答这些问题,会不会更容易让人理解呢?1. 批处理操作系统故名思意,这个时期的操作系统非常简单,同一时间只能处理一个任务/作业。把作业载入到内存中,这个处理完了,再处理下一个,一批一批的串行执行。这个时候,就没有什么进程、线程的概念了。因为IO设备比CPU慢太多了,所以它的缺点也很明显,CPU使用率不高,很多时候都是处于空闲状态。比如有两...原创 2021-04-12 20:46:51 · 388 阅读 · 1 评论 -
从“new和malloc的不同”出发看CC++的内存分配
1. 问题的引入new和malloc有什么不同?这是一个很经典的问题。他们共同点是,都是用进行动态内存分配的,但实现的方式不同。其中最根本的不同是,new是一个C++的操作符/关键字,而malloc是C/C++中一个函数。基于这个原因,它们又有以下的不同1. 参数,malloc需要指定申请内存的大小,new不需要,它会自己计算类中成员变量所占内存的大小2. 返回值,new返回类对象类型的指针,malloc返回void*3. 如果内存分配失败,new抛出std::bad_all...原创 2021-04-11 22:43:08 · 340 阅读 · 0 评论 -
epoll IO事件通知机制
下面是官方的手册,直译的话,太拗口,我就按照自己的理解翻译了。DESCRIPTION The epoll API performs a similar task to poll(2): monitoring multiple file descriptors to see if I/O is possible on any of them. The epoll API can be used either as an edge-trig...翻译 2021-04-22 23:15:05 · 613 阅读 · 0 评论