重点:计算机原理与内核 可以结合进程篇章看

声明:所有文章只作为学习笔记用,转载非原创
特别好的网站,图解好多原理
http://www.makelinux.net/](http://www.makelinux.net/
内核
https://www.cnblogs.com/alantu2018/p/8991171.html
命令检索
https://man.linuxde.net/top](https://man.linuxde.net/top

Linux 发展史
https://www.cnblogs.com/alantu2018/p/8991158.html

https://blog.csdn.net/andylauren/article/details/70094423

计算机原理

https://yq.aliyun.com/articles/742968?spm=a2c4e.11155472.0.0.5099127e8axmLL

32位CPU每次可以处理32个字位,即32bits=4Bytes
64位指的是CPU GPRs(General-Purpose Registers,通用寄存器)的数据宽度为64位,64位指令集就是运行64位数据的指令,处理器一次运行64bit数据

引导

https://blog.csdn.net/htttw/article/details/7217706

Linux内核在初始化之后会执行init进程,而init进程会挂载我们的根文件系统,但由于init程序也是在根文件系统上的,所以这就有了悖论。Linux采用两步走的方法来解决这个问题。Linux2.6版以前的方法是:除了内核vmlinuz之外还有一个独立的initrd.img映像文件,其实它就是一个文件系统映像,linux内核在初始化后会mount initrd.img作为一个临时的根文件系统,而init进程就是在initrd.img里的,然后init进程会挂载真正的根文件系统,然后umount initrd.img。但Linux2.6内核的实现方式却不太一样,虽然完成的功能是一样的。Linux2.6采用initramfs。initramfs:init ram filesystem,它是一个cpio格式的内存文件系统,制作的方法有两个,一个是http://blog.csdn.net/htttw/article/details/7215858介绍的,但这样做出来的initramfs是和内核vmlinuz分开的,因此我们需要在grub里写上initramfs的路径。而另一种方法是把内核和initramfs制作在一起成为一个文件,方法是在linux源码make menuconfig,然后General setup-->选择Initial RAM filesystem and RAM disk (initramfs/initrd) support,然后在Initramfs source file(s)里输入我们的initramfs目录,然后make bzImage。这种方法做出来的内核就只有一个文件,不需要指定initramfs了。

initramfs:init ram filesystem
Initrd 的英文全称是 initial ram disk,从字面意思来看,initi指linux的初始阶段,ram disk指RAM 盘。ram disk是一个基于ram的块设备,同其他存储设备一样,它不仅占据了一块固定的内存(只是它占用的[RAM内存](https://www.baidu.com/s?wd=RAM%E5%86%85%E5%AD%98&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao),而普通从此设备是ROM内存),而且其上也需要文件系统。

 https://zhidao.baidu.com/question/1495887129300510619.html 

计算机原理1.png
计算机原理2.png
计算机原理3.png
计算机原理4.png
计算机原理5.png
计算机原理6.png
整体架构
 https://blog.csdn.net/changexhao/article/details/78321295 


程序计数器(Program Counter)是用来存储下一条指令所在单元的地址。

程序执行时,PC的初值为程序第一条指令的地址,在顺序执行程序时,控制器首先按程序计数器所指出的指令地址从内存中取出一条指令,然后分析和执行该指令,同时将PC的值加1指向下一条要执行的指令。

(1)Linux系统的组成部分是内核+根文件系统。内核负责进程管理、内存管理、网络协议栈、文件系统、驱动程序和安全功能。
 运行中的系统环境可分为两层:内核空间(系统空间、系统模式)、用户空间(用户模式)。用户空间运行的是应用程序(进程或线程),内核空间运行的是内核代码(系统调用)。

#内核目录配置文件    --------------   /boot
vmlinuz是可引导的、压缩的内核。“vm”代表“Virtual Memory”
zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip压缩的。它们不仅是一个[压缩文件] https://baike.baidu.com/item/%E5%8E%8B%E7%BC%A9%E6%96%87%E4%BB%B6 ,而且在这两个文件的开头部分内嵌有gzip[解压缩] https://baike.baidu.com/item/%E8%A7%A3%E5%8E%8B%E7%BC%A9 代码。所以你不能用gunzip 或 gzip –dc[解包] vmlinuz。
vmlinux是未压缩的内核,vmlinuz是vmlinux的[压缩文件 
 https://blog.csdn.net/fjb2080/article/details/26240907 
 https://www.cnblogs.com/javawebsoa/archive/2013/07/24/3212564.html 
 


 1)核心文件:内核核心,一般为bzImage,通常位于/boot目录,
                          名称为/boot/vmlinuz-VERSION-release 
                          其中VERSION是内核版本号,release是本地版本号,制作和编译内核的人加上的版本号。
                          编译内核时,[   ]:N,表示不要此内核模块,[M]:Module,表示编译成模块,[*]:Y,表示编译进内核核心,内核支持模块的动态装载和卸载。

 2) https://www.cnblogs.com/duw76/p/9754625.html 
  

ramdisk:把内存中某一块空间作为磁盘用,用于实现系统初始化的、基于内存的磁盘设备。辅助性文件,并非必须,这取决于内核是否能直接驱动rootfs所在的设备:a) 目标设备驱动,例如SCSI设备的驱动;b) 逻辑设备驱动,例如LVM设备的驱动;c) 文件系统,例如xfs文件系统。 
                         ramdisk是一个简装版的根文件系统。
                         CentOS 5,6,7中的ramdisk:
                        CentOS 5:/boot/initrd-VERSION-release.img
                        CentOS 6,7:/boot/initramfs-VERSION-release.img
 (由initrd替换成initramfs的原因是避免双缓冲和双缓存,从而达到提速启动的目的)

 3)模块文件:/lib/modules/VERSION-release 如果安装了多个内核版本,在/lib/modules目录下将有多个内核文件目录。
 4)kernel object:内核对象,即内核模块,一般放置于/lib/modules/VERSION-release/。内核模块与内核核心版本一定要严格匹配。

升级内核
 https://www.jianshu.com/p/1261ed6f8399 
#更新内核后可以用这个命令查看
cat /boot/grub2/grub.cfg |grep menuentry

#模块文件
[root@master workshare]# cd /lib/modules 
 1)lsmod命令
 该命令用于显示Linux内核模块的状态信息。显示的内容来自于/proc/modules,包括3个字段:模块名称、模块大
[root@master modules]# cat /boot/config-3.10.0-957.12.1.el7.x86_64

 3)modprobe命令
 该命令用于从Linux内核中添加或移除模块。
 modprobe [-r] module_name

(1)内核信息获取
 uname命令
 该命令用来打印系统信息。
 uname [OPTION]...
 -r:内核的release号
 -n:主机名
 -v:编译版本
 -a:所有信息
 此命令查看的是文件:/boot/vmlinuz-VERSION-release中的系统信息。

 https://segmentfault.com/a/1190000010164083 

#伪文件系统
(1)伪文件系统目录
 /proc:该目录下的文件为内核状态和统计信息的输出接口,同时,还提供一个配置接口:/proc/sys;
 只读参数:信息输出;例如/proc/#/*
 可写参数:可接受用户指定一个“新值”来实现对内核某功能或特性的配置,可写参数位于/proc/sys/目录下。
 /proc/sys目录下的net/ipv4/ip_forward相当于net.ipv4.ip_forward。

 #中断
https://www.cnblogs.com/edver/p/7260696.html
中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续运行被暂时中断的程序。Linux中通常分为外部中断(又叫硬件中断)和内部中断(又叫异常)
CPU中断处理:
CPU的中断处理是优先级最高的任务之一。中断分为:hard interrupte 和 soft interrupt.

因为中断发生,就会去运行中断处理程序,也就导致了context switch,所以过多的中断也会导致性能的下降。

/proc/slabinfo
http://blog.itpub.net/15480802/viewspace-753819/
https://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator

ZONE_HIGHMEM内核空间   ZONE_NORMAL用户空间
 https://blog.csdn.net/andylauren/article/details/70094423 

slab分配器概述
https://www.cnblogs.com/tolimit/p/4566189.html
https://www.cnblogs.com/pengdonglin137/p/3878552.html
这里我们简称为页框分配器,在页框分配器中主要是管理物理内存,将物理内存的页框分配给申请者,而且我们知道也可页框大小为4K(也可设置为4M),这时候就会有个问题,如果我只需要1KB大小的内存,页框分配器也不得不分配一个4KB的页框给申请者,这样就会有3KB被白白浪费掉了。为了应对这种情况,在页框分配器上一层又做了一层SLAB层,SLAB分配器的作用就是从页框分配器中拿出一些页框,专门把这些页框拆分成一小块一小块的小内存,当申请者申请的是小内存时,系统就会从SLAB中获取一小块分配给申请者。

cache_chain 的每个元素都是一个 kmem_cache 结构的引用(称为一个 cache)。它定义了一个要管理的给定大小的对象池。

#虚拟内存工作原理 一定要看
https://www.cnblogs.com/hellobb/p/10451583.html


库文件

 https://www.cnblogs.com/jiftle/p/11584780.html 
glibc是什么,以及与gcc的关系?
glibc是gnu发布的libc库,也即c运行库。glibc是linux 系统中最底层的api(应用程序开发接口),几乎其它任何的运行库都会倚赖于glibc。glibc除了封装linux操作系统所提供的系统服务外,它本 身也提供了许多其它一些必要功能服务的实现,主要的如下:
(1)string,字符串处理
(2)signal,信号处理
(3)dlfcn,管理共享库的动态加载
(4)direct,文件目录操作
(5)elf,共享库的动态加载器,也即interpreter
(6)iconv,不同字符集的编码转换
(7)inet,socket接口的实现
(8)intl,国际化,也即gettext的实现
(9)io
(10)linuxthreads
(11)locale,本地化
(12)login,虚拟终端设备的管理,及系统的安全访问
(13)malloc,动态内存的分配与管理
(14)nis
(15)stdlib,其它基本功能

----------内核篇章

https://segmentfault.com/a/1190000020454889

  1. 虚拟地址分为内核空间和用户空间,同时虚拟内存模型是一个倒着的栈,栈底是高地址。如下所示:

  2. 虚拟地址和物理地址之间是要通过一个东西关联的,就像一个索引,而这个东西就是页表,Linux 用的是四级页表

内核空间
0-3G 用户空间 0x00000000 ~ 0xbfffffff
3-4G 内核空间 0xc0000000 ~ 0xffffffff
64位地址空间
https://blog.csdn.net/hhhanpan/article/details/80548687
https://blog.csdn.net/liuyez123/article/details/51096914
https://blog.csdn.net/mzjmzjmzjmzj/article/details/84713351

----------三种不同的内存地址
逻辑地址(logical address)包含在linux实际指令中的地址,即分段式地址,是对应的硬件平台段式管理转换前地址
由16位的段选择符(segment selector)和32位的偏移量组成。
线性地址(linear address)(虚拟地址(virtual address))是一个32位无符号整数,可以表示4G的地址,值范围从0x00000000-0xffffffff。
线性地址则对应了硬件页式内存的转换前地址。
物理地址(physical address)
用32位或者36位无符号整数表示。用于内存芯片级的单元寻址,与处理器和CPU连接的地址总线相对应。
---------三者之间的关系逻辑地址------>分段单元------>线性地址------>分页单元------>物理地址

每个用户进程都有独立的用户空间(虚拟地址0-3),而内核空间是唯一的(相当于共享)

task_struct被称为进程描述符(process descriptor),因为它记录了这个进程所有的context。其中有一个被称为'内存描述符‘(memory descriptor)的数据结构mm_struct,抽象并描述了Linux视角下管理进程地址空间的所有信息。

https://blog.csdn.net/yangkuanqaz85988/article/details/52403726

Linux 对进程地址空间有个标准布局,地址空间中由各个不同的内存段组成 (Memory Segment),主要的内存段如下:

  • 程序段 (Text Segment):可执行文件代码的内存映射
  • 数据段 (Data Segment):可执行文件的已初始化全局变量的内存映射
  • BSS段 (BSS Segment):未初始化的全局变量或者静态变量(用零页初始化) Block Started bySymbol
  • 堆区 (Heap) : 存储动态内存分配,匿名的内存映射
  • 栈区 (Stack) : 进程用户空间栈,由编译器自动分配释放,存放函数的参数值、局部变量的值等
  • 映射段(Memory Mapping Segment):任何内存映射文件

一个程序本质上都是由 bss段、data段、text段三个组成的。
  这样的概念,不知道最初来源于哪里的规定,但在当前的计算机程序设计中是很重要的一个基本概念。
  而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题。
在采用段式内存管理的架构中(比如intel的80x86系统),bss段通常是指用来存放程序中未初始化的全局变量的一块内存区域,
  一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。
比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。
  text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;
 而bss段不在可执行文件中,由系统初始化。

每个区域是依靠着两个指针进行维护的,比如[start_data,end_data)是用来维护data段,[start_code,end_data)用来维护code段,[start_brk,brk),用来维护heap和heap的指针。[start_stack,end_stack)是用来维护stack段空间范围。mmap_base是维护共享映射区的起始地址。bss段表示的是所有的未初始化的全局变量,为了效率,对处在bss段的变量,将它们匿名映射到“零页”,这样提高了程序的加载效率。

3、 内核初始化以后,根据实际物理内存的大小,计算出 high_memory、VMALLOC_START、VMALLOC_END 的值。并为“内核直接映射”空间建立好映射关系,所有的物理内存都可以通过此空间进行访问。

task_structs1.png

https://www.jb51.net/article/123056.htm

mm_structs.png

task_struct 到 mm_struct

这就是我们所说的由task_struct到mm_struct,进程的地址空间的分布。
(https://blog.csdn.net/qq_26768741/article/details/54375524

task_structs2.png


struct mm_struct {
  struct vm_area_struct * mmap;  //指向虚拟区间(VMA)的链表
  struct rb_root mm_rb;      //指向线性区对象红黑树的根
  struct vm_area_struct * mmap_cache;   //指向最近找到的虚拟区间
  unsigned long(*get_unmapped_area) (struct file *filp,
  unsigned long addr, unsigned long len,
  unsigned long pgoff, unsigned long flags);//在进程地址空间中搜索有效线性地址区
  unsigned long(*get_unmapped_exec_area) (struct file *filp,
    unsigned long addr, unsigned long len,
    unsigned long pgoff, unsigned long flags);
  void(*unmap_area) (struct mm_struct *mm, unsigned long addr);//释放线性地址区间时调用的方法
  unsigned long mmap_base;        /* base of mmap area */
  unsigned long task_size;        /* size of task vm space */
  unsigned long cached_hole_size;
  unsigned long free_area_cache;     //内核从这个地址开始搜索进程地址空间中线性地址的空闲区域
  pgd_t * pgd;              //指向页全局目录
  atomic_t mm_users;           //次使用计数器,使用这块空间的个数  
  atomic_t mm_count;           //主使用计数器
  int map_count;             //线性的个数
  struct rw_semaphore mmap_sem;      //线性区的读/写信号量
  spinlock_t page_table_lock;       //线性区的自旋锁和页表的自旋锁
  struct list_head mmlist;       //指向内存描述符链表中的相邻元素
  /* Special counters, in some configurations protected by the
  * page_table_lock, in other configurations by being atomic.
  */
  mm_counter_t _file_rss; //mm_counter_t代表的类型实际是typedef atomic_long_t
  mm_counter_t _anon_rss; 
  mm_counter_t _swap_usage;
  unsigned long hiwater_rss;  //进程所拥有的最大页框数
  unsigned long hiwater_vm;   //进程线性区中最大页数
  unsigned long total_vm, locked_vm, shared_vm, exec_vm;
  //total_vm 进程地址空间的大小(页数)
  //locked_vm 锁住而不能换出的页的个数
  //shared_vm 共享文件内存映射中的页数
  unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;
  //stack_vm 用户堆栈中的页数
  //reserved_vm 在保留区中的页数或者在特殊线性区中的页数
  //def_flags 线性区默认的访问标志
  //nr_ptes 进程的页表数
  unsigned long start_code, end_code, start_data, end_data;
  //start_code 可执行代码的起始地址
  //end_code 可执行代码的最后地址
  //start_data已初始化数据的起始地址
  // end_data已初始化数据的最后地址
  unsigned long start_brk, brk, start_stack;
  //start_stack堆的起始位置
  //brk堆的当前的最后地址
  //用户堆栈的起始地址
  unsigned long arg_start, arg_end, env_start, env_end;
  //arg_start 命令行参数的起始地址
  //arg_end命令行参数的起始地址
  //env_start环境变量的起始地址
  //env_end环境变量的最后地址
  unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
  struct linux_binfmt *binfmt;
  cpumask_t cpu_vm_mask; //用于惰性TLB交换的位掩码
  /* Architecture-specific MM context */
  mm_context_t context; //指向有关特定结构体系信息的表
  unsigned int faultstamp;
  unsigned int token_priority;
  unsigned int last_interval;
  unsigned long flags; /* Must use atomic bitops to access the bits */
  struct core_state *core_state; /* coredumping support */
#ifdef CONFIG_AIO
  spinlock_t       ioctx_lock; //用于保护异步I/O上下文链表的锁
  struct hlist_head    ioctx_list;//异步I/O上下文
#endif
#ifdef CONFIG_MM_OWNER
  struct task_struct *owner;
#endif
#ifdef CONFIG_PROC_FS
  unsigned long num_exe_file_vmas;
#endif
#ifdef CONFIG_MMU_NOTIFIER
  struct mmu_notifier_mm *mmu_notifier_mm;
#endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
  pgtable_t pmd_huge_pte; /* protected by page_table_lock */
#endif
#ifdef __GENKSYMS__
  unsigned long rh_reserved[2];
#else
  //有多少任务分享这个mm OOM_DISABLE
  union {
    unsigned long rh_reserved_aux;
    atomic_t oom_disable_count;
  };
  /* base of lib map area (ASCII armour) */
  unsigned long shlib_base;
#endif
};

每个进程的用户空间用mm_struct描述,即task_struct.mm。
https://www.cnblogs.com/yamadie/p/3493364.html
https://www.sandpile.org/x86/desc.htm

我们知道,在linux操作系统中,CPU在执行一个进程的时候,都会访问内存。
但CPU并不是直接访问物理内存地址,而是通过虚拟地址空间来间接的访问物理内存地址。
所谓的虚拟地址空间,是操作系统为每一个正在执行的进程分配的一个逻辑地址,在32位机上,其范围从0 ~ 4G-1。操作系统通过将虚拟地址空间和物理内存地址之间建立映射关系,让CPU间接的访问物理内存地址。
--------通常将虚拟地址空间以512Byte ~ 8K,作为一个单位,称为页,并从0开始依次对每一个页编号。这个大小通常被称为页面
将物理地址按照同样的大小,作为一个单位,称为框或者块,也从0开始依次对每一个框编号。
操作系统通过维护一张表,这张表上记录了每一对页和框的映射关系。如图:


页 页表 页框(块).png

它们都是内核对内存的分块单位,大小通常是对应的。通常理解页是虚拟页,页框是物理页。没有谁包含谁的关系。不过,一个物理页可以映射给多个进程,也就是说一个页框可以映射到多个页勉强理解成你说的意思吧。

四种页表分别称为: 页全局目录、页上级目录、页中间目录、页表
PGD:page Global directory(47-39), 页全局目录
PUD:Page Upper Directory(38-30),页上级目录
PMD:page middle directory(29-21),页中间目录
PTE:page table entry(20-12),页表项

css,ss,ds,es,fs,gs 其中前三个有特殊用途,后三个是通用段寄存器。

#怎么理解栈
[https://www.zhihu.com/question/57013926](https://www.zhihu.com/question/57013926)

3. C语言书里面讲的堆、栈大部分都是用户态的概念,用户态的堆、栈对应用户进程虚拟地址空间里的一个区域,栈向下增长,堆用malloc分配,向上增长。

4. 用户空间的堆栈,在task_struct->mm->vm_area里面描述,都是属于进程虚拟地址空间的一个区域。

 


 
linux IO 栈
[https://blog.csdn.net/lsgqjh/article/details/99686976](https://blog.csdn.net/lsgqjh/article/details/99686976)


#linux 无处不在的缓存
[https://blog.csdn.net/lsgqjh/article/details/99686976](https://blog.csdn.net/lsgqjh/article/details/99686976)


你可能感兴趣的:(重点:计算机原理与内核 可以结合进程篇章看)