目录
int fun1(){ union test{ char c; int i; }; test t; t.i = 1; //如果是大端,则t.c为0x00,则t.c != 1,反之是小端 return (t.c == 1); }
c 没有 赋初值,所以没有 有效字节
malloc如何申请内存
- malloc 通过 brk() 方式申请的内存,free 释放内存的时候,并不会把内存归还给操作系统,而是缓存在 malloc 的内存池中,待下次使用;
- malloc 通过 mmap() 方式申请的内存,free 释放内存的时候,会把内存归还给操作系统,内存得到真正的释放。
-
频繁通过 mmap 分配的内存话,不仅每次都会发生运行态的切换,还会发生缺页中断(在第一次访问虚拟地址后),这样会导致 CPU 消耗较大。
为了改进这两个问题,malloc 通过 brk() 系统调用在堆空间申请内存的时候,由于堆空间是连续的,所以直接预分配更大的内存来作为内存池,当内存释放的时候,就缓存在内存池中。
等下次在申请内存的时候,就直接从内存池取出对应的内存块就行了,而且可能这个内存块的虚拟地址与物理地址的映射关系还存在,这样不仅减少了系统调用的次数,也减少了缺页中断的次数,这将大大降低 CPU 的消耗。
class LRUCache {
list<pair<int, int>> cache;//创建双向链表
unordered_map<int, list<pair<int, int>>::iterator> map;//创建哈希表
int cap;
public:
LRUCache(int capacity) {
cap = capacity;
}
int get(int key) {
if (map.count(key) > 0){ // 已经存在
auto temp = *map[key];
cache.erase(map[key]);
map.erase(key);
cache.push_front(temp);
//push_front() 在列表的开头插入新元素并将列表的大小增加一
map[key] = cache.begin();//映射头部
return temp.second;
}
return -1;
}
void put(int key, int value) {
if (map.count(key) > 0){ //已经存在
cache.erase(map[key]);
map.erase(key);
}
else if (cap == cache.size()){ //满了
auto temp = cache.back();
map.erase(temp.first);
cache.pop_back(); //pop_back:移除末元素
}
cache.push_front(pair<int, int>(key, value)); //新建
map[key] = cache.begin();//映射头部
}
};
std::move 就是实现了 浅拷贝,同时消灭 原本的 被拷贝者 地址中放的东西
线程和进程
进程: 程序运行的实例,资源分配的单位 ,三种、五种基本状态 发生页表的切换过程开销比较大,
线程:CPU调度的最小单位,线程是进程当中的一条执行流程
线程与进程的区别:
(1)一个线程从属于一个进程;一个进程可以包含多个线程。
(2)一个线程挂掉,对应的进程挂掉;一个进程挂掉,不会影响其他进程。
(3)进程是系统资源调度的最小单位;线程CPU调度的最小单位。
(4)进程系统开销显著大于线程开销;线程需要的系统资源更少。
(5)进程在执行时拥有独立的内存单元,多个线程共享进程的内存,如代码段、数据段、扩展段;但每个线程拥有自己的栈段和寄存器组。
(6)进程切换时需要刷新TLB并获取新的地址空间,然后切换硬件上下文和内核栈,线程切换时只需要切换硬件上下文和内核栈。
(7)通信方式不一样。
孤儿进程:孤儿就是没有爸爸,所以就是父进程退出,而它的子进程还在继续,这些进程就会成为孤儿进程
消息队列:保存在内核中的消息链表,通信过程中存在用户态和内核态之间的数据拷贝开销
消息队列的声明周期随着内核操作系统关闭 或者 关闭 消息队列的操作,而关闭,不会随着进程的关闭而关闭
进程间通信方式:
线程间通信方式:
临界区 ,每个线程都会访问的那段代码
互斥量: 拥有互斥对象的线程才可以访问
死锁如何解决:
资源一次性分配,不要获得一定资源,又想获得已经被其他进程占有的资源
也可以剥夺 已被进程占有的资源
资源的分配,递增请求,释放相反
使用mmap的场景包括:
-
文件的映射:可以将文件映射到进程的地址空间,进而实现对文件的读写操作。
-
共享内存:多个进程可以通过映射同一块物理内存区域实现共享内存,从而进行进程间通信。
-
匿名映射:创建一个无关联的映射区,通常用于大块的动态内存分配。
-
零拷贝:在网络编程中,使用mmap可以减少数据从内核空间到用户空间的拷贝次数,提高数据传输效率。