模板函数底层实现:
编译器会对模板函数编译两次,一次是在声明部分的地方对模板本身进行编译;二次是在调用的地方对参数进行替换后的代码进行编译。函数模板只有实例化后才是真正的函数。
操作系统:
操作系统的功能:
CPU管理:cpu的管理和分配,主要是进程的管理;
内存管理:内存的管理和分配,主要是利用虚拟内存的方式;
外存管理:外存管理和分配,将外存以文件的方式提供;
I/O管理:对输入/输出设备的统一管理。
内核:可以控制操作系统中的所有内容。
内核态和用户态:
内核具有很高的权限,可以控制cpu、内存和输入输出设备,处于控制权限的考虑,大多数操作系统把内存分为两个区域:
内核空间:这个区域只能是内核程序可以访问;
用户空间:这个内存空间只能是用户的应用程序可以访问,权限比较小。
用户空间的代码只能访问一个局部的内存空间,内核空间代码可以访问全部的内存空间代码,当程序使用用户空间时,我们就说程序运送在用户态执行;当程序使用内核空间时,我们就说程序在内核态执行。
用户态和内核态如何切换:
应用程序如果需要进入内核空间,就需要进行系统调用,来进入内存空间。当应用程序使用系统调用时,会触发中断,CPU中断当前执行的用户程序,去执行内核程序,处理完成后,CPU把权限还给用户程序,回到用户态执行。
并发和并行的区别:
并发是在一段时间内,多个任务状态都会被处理,但是在同一时刻只处理一个任务。单核处理并发就是利用时间片的轮转,切换的足够快;
并行:就是在同一时刻,多个任务同时执行;需要多核处理器进行处理;
进程上下文切换:
进程上文:我们把已执行的进程指令和数据在相关寄存器与堆栈中的内容;
进程正文:正在执行的进程指令和数据在相关寄存器与堆栈的内同;
进程下文:待执行的进程指令和数据在相关寄存器与堆栈的内容。
linux内核中:包括虚拟地址空间和硬件上下文。
1、进程地址空间切换:进程地址空间是进程所拥有的虚拟内存地址;只保证了进程访问指令数据时访问的是自己的地址空间;
2、处理器状态(硬件上下文)切换:保证进程内核栈和执行流的切换,会将当前进程的硬件上下文保存在进程所管理的一块内存,然后将即将执行的进程的硬件上下文从内存中恢复到寄存器,有了这两步的切换过程保证了进程运行的有条不紊,当然切换的过程是在内核空间完成,这对于进程来说是透明的
ASID机制,ASID(Address Space Identifer 地址空间标识符),用于区别不同进程的页表项;
僵尸进程:
就是进程处于终止状态,但仍存在在进程列表中;僵尸进程一般发生在有父子关系的进程中,子进程退出而父进程没有调用wait()或waitpid(),子进程的进程描述符仍保存在系统中。
孤儿进程:
一个父进程退出, 而他的一个或多个子进程仍在运行,孤儿进程会被init进程收养(进程id = 1),不会危害系统
进程调度算法:先来先服务、短作业优先、优先级调度、时间片轮转、最短剩余时间优先。
虚拟内存:是操作系统的一种机制,将不同进程的虚拟地址和不同的内存的物理地址映射起来。
实现:
在装入程序时,不必将其全部装入到内存,而只需将当前需要执行的部分页面装入到内存,就可让程序开始执行;
在程序执行过程中,如果需执行的指令或访问的数据尚未在内存(称为缺页)。则由处理器通知操作系统将相应的页面调入到内存,然后继续执行程序;
另一方面,操作系统将内存中暂时不使用的页面调出保存在外存上,从而腾出更多空闲空间存放将要装入的程序以及将要调入的页面。
内存分段:程序是有若干个逻辑分段组成,分为代码段、数据段、堆段、栈段,不同的分段有不同的属性,所以就用分段的形式分离出来;
分段的机制下,把虚拟内存地址由两部分组成:段号和偏移量;
虚拟地址和物理地址通过段表进行映射,段表包括:短号、段基地址和段的界限。
页:分页是把虚拟和物理内存分割成一块块固定大小的块;
分段和分页的区别:
段是信息的逻辑单位,根据不同的功能划分的,大小不定;页是大小是系统决定的,是信息的物理单位;
-
段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的 ;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的。
-
段的大小不固定,有它所完成的功能决定;页的大小固定,由系统决定
-
段向用户提供二维地址空间;页向用户提供的是一维地址空间
-
段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制。
什么是交换空间
操作系统把内存分成一小块一小块的小内存,每块小内存称为页,当内存不足时,把某页的内容转移到磁盘上,已释放内存,这个过程叫做交换空间。
零拷贝:
传统的I/O,数据读入和写入是用户空间到内核空间的来回赋值,这期间发生多次用户态和内核态的切换,以及多次拷贝。而零拷贝mmap()函数直接将内核缓冲区的数据映射到用户态;另一种调用sendFile;
set:
set不允许有两个相同的键值,键值的属性是const,底层是rb-tree;
multiset:
允许有两个相同的键值,和set性质相同
为什么set没有[],因为map的key由value,set没有value。
map:
skia:
skia是一个2D向量图形处理函数库,包括字型、坐标转换,点阵图都有高效的表现,并且我们的一些其他的功能比较好的支持,例如pdf文件、svg文件导出,渐变效果、高斯模糊效果、背景模糊等特效的支持。
渲染缓存:
首先了解一个前提:画布的概念,是我们产品,渲染缓存采用了画布的缩放倍数为key,缓存当前画布的图像,画布的图像是把画布分块进行保存,每块画布的image使用lru进行管理,缓存更新时,是某个区域的元素变化,只更新这个区域内的iamage进行更新。
碰撞检测模块:
这个模块经历了轮询检测到rtree的迭代,rtree是空间索引,是对btree的扩展。
那些函数不能是虚函数:
构造函数:构造函数初始化对象,派生类必须知道基类是什么,才能进行初始化;虚函数表在构造函数中进行初始化。
内联函数:
静态函数:
友元函数:
普通函数:
重载:是函数的参数不同,顺序不同
重写:
多线程的栈空间为什么是私有的?
栈空间是一段连续的空间,假如栈空间是共享的话,
volatile的作用:
- 阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回;
- 阻止编译器调整操作volatile变量的指令顺序;
-
无法阻止 CPU 动态调度换序。