Linux中的内存管理机制
程序在运行时所有的数据结构的分配都是在堆和栈上进行的,而堆和栈都是建立在内存之上。内存作为现代计算机运行的核心,CPU可以直接访问的通用存储只有内存和处理器内置的寄存器,所有的代码都需要装载到内存之后才能让CPU通过指令寄存器找到相应的地址进行访问。
程序在运行时所有的数据结构的分配都是在堆和栈上进行的,而堆和栈都是建立在内存之上。内存作为现代计算机运行的核心,CPU可以直接访问的通用存储只有内存和处理器内置的寄存器,所有的代码都需要装载到内存之后才能让CPU通过指令寄存器找到相应的地址进行访问。
惊群现象是在多进程或者多线程场景下,多个进程或者多个线程在同一条件下睡眠,当唤醒条件发生的时候,会同时唤醒这些睡眠的进程或者线程,但是只有一个是可以成功执行的,而其他的进程或者线程被唤醒后存在着执行开销的浪费。
单例模式(Singleton)是用于保证在整个应用程序的生命周期中的任何一个时刻,单例类的实例都只存在一个或者不存在。许多设备管理器常常设计为单例模式,比如很经典的电脑打印程序的设计,一台计算可以链接多台打印机,但是在整个打印过程中只能有一个打印程序的实例,不能让多台打印机打印同一份文件。
对于较多数量的文件描述符的监听无论是select还是poll系统调用都显得捉襟见肘,正如前文Unix/Linux 中的五种 I/O 模型中对select/poll与epoll性能对比中所分析的,poll每次都需要将所有的文件描述符复制到内核,内核本身不会对这些文件描述符加以保存,这样的设计就导致了poll的效率的低下。而epoll则对此做了相应的改进,不是epoll_wait的时候才传入fd,而是通过epoll_ctl把所有fd传入内核,再一起”wait”,这就省掉了不必要的重复拷贝。其次,在 epoll_wait时,也不是把current轮流的加入fd对应的设备等待队列,而是在设备等待队列醒来时调用一个回调函数(当然,这就需要“唤醒回调”机制),把产生事件的fd归入一个链表,然后返回这个链表上的fd。另外,epoll机制实现了自己特有的文件系统eventpoll filesystem。本文将从linux内核源码(linux v2.6.26.8)角度出发对epoll的实现机制加以总结梳理。
在之前的malloc和free的实现原理解析一文中,我主要分析了C语言中常用的两个内存管理函数malloc()
和free()
的相关细节。内存管理则是主要通过运算符new
, new[]
, delete
和delete[]
来实现。按照C++标准new/delete
和new[]/delete[]
并不是C++中的函数,而是C++中的关键字。之所以有这样的区别,C++中在对象创建时需要自动执行构造函数,而在对象销毁时需要自动执行对象的析构函数。而malloc()/free()
则是库函数而非运算符,不在编译器控制权限之内,无法把执行构造函数和析构函数的任务强加于malloc()/free()
。
IO模型的选择在Linux网络编程中十分重要,在Unix/Linux环境中主要提供了五种不同的IO模型,分别是阻塞式IO、非阻塞式IO、IO多路复用、信号驱动式IO和异步IO。
“内存碎片”描述了一个系统中所有不可用的空闲内存。这些资源之所以仍然未被使用,是因为负责分配内存的分配器使这些内存无法使用,原因在于空闲内存以小而不连续方式出现在不同的位置,内存分配器无法将这些内存利用起来分配给新的进程。由于分配方法决定内存碎片是否是一个问题,因此内存分配器在保证空闲资源可用性方面扮演着重要的角色。