杂乱知识点
一些杂乱的知识点
杂乱知识点 01
目录
TODO
protobuf为啥快
- 数据压缩程度高
- 解析速度快
protobuf基本
使用tag|value方法存储数据。tag中包含数据序号与数据类型。从而避免了json的字符串解析。
tag生成办法:
1 | static int makeTag(final int fieldNumber, final int wireType) { |
在上述代码中,fieldNumber为序号,wireType为数据类型。
有符号整型使用zigzag编码,减少了存储空间。
非varint类型数字采用小端序列存储。
字符串类型采用**tag|len|str|**方法存储。
有符号整型的压缩
ZigZag主要是将无符号数字0,1,2,3转换为有符号数字0,-1,1,-2等。
之后我们可以压缩数据。将32位数据每次取7位,如果非最低字节则补1,其余补0.然后将低字节与高字节反转。(小端)
断点调试原理
断点调试,即在断点处插入int 3指令,OS向进程发送SIGTRAP信号,使得当前进程暂停,交给父进程去处理。
按下ctrl-c后会发生什么
发送SIGINT信号给前台进程组所有进程,强行终止程序执行。
进程间通信IPC InterProcessCommunication
- 匿名管道PIPE
- 半双工,只能一个方向流动,固定读写端
- 只能有亲缘关系进程之间的通信
- 类似于文件,可以read write,但仅存于内存
- 命名管道FIFO
- 可以在无关进程之间交换数据
- 属于特殊的文件形式存在于文件系统中,有路径名
- 消息队列
- 包含消息类型,存在优先级,有特定格式
- 读取时候可以按类型读取
- 信号量
- 发送信号,主要用于同步进程
- 原子操作
- 可以计数
- 共享内存
- 最快,直接读内存,效率高
- 可以多进程同时操作,需要同步
- 通常和信号量同时使用
- 共享内存不需要涉及内核,所以最快
TOP-K问题
- quick select:快排思想,省去一半 平均On 最坏On2
- 建堆 nlogk 使用priority_queue来建,默认是大于号
- 建堆可以分布式
- 可以哈希去重
B树与B+树
B树
- 多叉树
- 关键词集合分布在整个树中
- 性能优异,等价于二分查找
- 关键词只出现在一个结点中
- 自动层次控制
B+树
- 用于数据库,文件系统等
- 数据稳定有序,自底向上插入,性能稳定
- 结点关键词只用于索引,不存储
- 叶子结点存储数据,并且添加链表指针
HTTP状态码
见restful api
布隆过滤器
使用k个哈希函数,将key映射成k个整数,然后将对应二进制位置为1。
有一定概率判断出错。
无法删除。
红黑树
红黑树,自平衡的类平衡树,非严谨平衡。有以下特点
- 结点或黑或红
- 根是黑的
- 红色无法相连,黑色可以
- 根到所有叶子结点经过的黑色结点个数相同
- 插入结点过程
- 新插入的结点为红色
- 如果为根结点,则标记成黑色
- 如果parent不是黑色且不是root
- uncle为红
- 将parent and uncle标记为黑
- 祖父标记为红
- 与祖父相同颜色
- uncle为黑 触发旋转
- 新结点为左左,则提绳子
- 左右,则将亲子换位,然后左左
- 右右同理
- 右做,则换位后右右
- uncle为红
- 统计性能比avl更好
进程与线程
- 进程
- 系统进行资源调度和分配的基本单位,实现操作系统的并发。
- 进程内的线程共享堆,全局变量,静态变量,文件等。
- 进程之间同步基于IPC。
- 不同进程之间挂掉不影响
- 线程
- CPU调度和分配的基本单位,实现进程内部的并发。
- 有独立的寄存器组,指令计数器,自己的栈。
- 线程之间同步基于内存。
- 同一进程的线程会相互影响
虚拟地址
操作系统采用虚拟地址的方法,给予程序虚拟地址,由mmu翻译成物理地址,使得每个程序都认为自己独占了内存。
好处:
- 抽象化,便于管理,分配,调度,便于利用碎片
- 扩大地址空间
- 便于共享
- 可以保护内存空间,难以访问到其他进程的内存
坏处: - 增加了开销,如翻译地址,额外的数据结构,磁盘io
- 可能浪费内存
缺页中断
在malloc和mmap调用时候,只构建了虚拟地址,没有分配物理内存,当访问到的时候引起缺页异常,保护现场,分析原因,调用对应的处理函数,恢复。
系统锁
mutex互斥锁
- 读写都锁,统一时刻只能有一个访问
rwlock读写锁
- 写锁,可以有很多读,但写的时候不能读
spin自旋锁
- 同一时刻只有一个访问,但不会睡眠,而是自旋,一直保持活跃
RCU锁
- 写时候拷贝,对副本进行修改,在没有操作临界区时候去回调。
可重入锁
同一线程可以再次锁,不会死锁
乐观锁
- 认为拿数据的时候别人不会修改,读取的时候不会上锁。
- 在提交更新的时候使用版本号或者CAS算法来确定
- CAS:当期望与实际符合的时候,才会更新替换,否则不会
悲观锁
- 在每次读取或修改都会上锁
- 不正确的代码容易导致死锁
进程状态
创建-就绪-执行-等待-终止
死锁
- 互斥:资源只能被一个进程使用
- 请求与保持:在请求资源时候,不会放开自己已经持有的资源
- 不剥夺:不能强行剥夺
- 循环等待:各个进程循环等待
- 银行家算法:三个矩阵claimd allocated need,只要剩余不为负数则贷款给过去
几种io
缓存IO:先拷贝到page cache,再拷贝到目标空间 效率较慢
select poll epoll本质都是同步io,用于io复用
select在socket被唤醒之后,进程从阻塞状态被加入工作队列,在工作队列中正运行的时候,会遍历一遍fd set来找到被唤醒的sock,从而处理。
select调用后会阻塞,知道fd就绪或者超时,并且通过遍历fd数组找到目标fd。描述符数量一半为1024。
poll使用pollfd指针来实现,返回后采用轮询来返回就绪的fd
epoll作用:先调用epoll create,然后用epoll ctl加入需要处理的sock,最后用epoll wait等待。在创建对象时候,会创建一个epollfd,用ctl来处理。当中断执行的时候,会加入到epollfd里面的readylist中。
epoll存在LT模式和ET模式,LT:应用程序不立即处理,ET则是立即处理。
- BIO 同步阻塞
- 读取写入必须阻塞再一个线程里面完成,过程阻塞
- NIO 同步非阻塞
- 不阻塞,而是反复查询
- AIO 异步io
- 读取写入异步,内核读取了则发送信号
下一个排列算法
基本原则:把右边的稍微大一点的元素挪到前面来,并且使它不会到过于前面的位置。
从右向左,找到第一个ai小于ai+1的i,我们可以得知从i+1到末尾是完全降序的。再从右往左找到第一个大于ai的j。交换ai与aj,这时候ai+1到n是完全降序,因此然后将ai+1到末尾变成reverse,使其变成升序,也就是后半字典序最小,即为下一个排列。
丑数二分
如何找到比x小的,可以被abc整除的数的个数:使用集合,x/a+x/b+x/c-x/lcm(ab)-x/lcm(ac)-x/lac(bc)+x/lcm(abc)即可。
根据此原则,可以二分答案,找到模糊的界。
再根据该数,求出精确的边界。由n-min(n%a,n%b,n%c)可以得到。
为什么要等2MSL的时间,time_await状态才会结束
- 为了可靠地终止TCP连接。最后一次ACK可能会传输失败,因此需要等待。
- TCP分节可能会因为路由器异常而迷路,此时可能会有迟来的TCP分节到达,需要在到达的时候保证不返回,及时丢弃。
如何处理time_await过多的状态
MSL时间常用是30s,1min和2min。因此对于高并发短连接业务来说,会消耗大量端口,而且2MSL时间相对于业务逻辑过长。因此需要处理。
在系统设置中开启重用和快速回收。
如何查看进程
ps指令,或者进proc查pid,netstat显示网络链接