秋招

面经部分

一个端口被占用了,怎么查到是哪个进程占用的
lsof -i:port
netstat -tunlp | grep port
C++内存分配的方式
栈 堆 自由储存 全局/静态变量 常量区
C内存分配的方式
栈 共享储存区 堆区 bss(未初始化数据段) 已初始化数据段
文本区
进程和线程的区别(进阶版回答)
https://kenby.iteye.com/blog/1014039
判断回文链表
https://blog.csdn.net/sunao2002002/article/details/46918645
利用快慢指针找出后半段,然后反转后半段链表,然后判断是否回文

原子操作和互斥锁的实现
http://www.voidcn.com/article/p-dsqrguvl-gc.html
主要利用了futex ,futex的远离操作利用的x86的指令
布隆过滤器
https://zhuanlan.zhihu.com/p/43263751
HTTP格式
https://blog.csdn.net/H517604180/article/details/79802914
页面置换算法
https://blog.csdn.net/wangsifu2009/article/details/6757352
长链接转短链接
https://blog.csdn.net/qq_33530388/article/details/78066538
发号+LRU
static在各种情况下的声明周期和作用域

https://www.cnblogs.com/bigclould/p/9322248.html

快排为啥比堆排快
https://www.zhihu.com/question/23873747

TCP初始序列号为什么是随机的

https://blog.csdn.net/qq_40910541/article/details/88760627

安全问题,反正别人伪造序列号

CLOSE_WAIT过多产生的原因及解决办法

https://my.oschina.net/lenglingx/blog/1535887

修改内核参数

https://blog.51cto.com/netlin/1167446

创建一个线程需要消耗什么资源
寄存器 栈,程序计数器,可以提一 下 __thread

栈的大小是固定的吗
https://blog.csdn.net/liyuanyes/article/details/44097731
是固定的,但是可以自己修改,ulimit -s ans
怎么测量栈的大小
每个线程都有个栈,从而间接说明线程的大小

栈与堆的分配速度

https://www.jianshu.com/p/770d279bb531

内存泄漏
https://blog.csdn.net/Clever_Pig/article/details/75050398
解决方法还是用智能指针,但是介绍内存泄露时,可以介绍下
系统资源泄露

vi 搜索 替换

https://www.cnblogs.com/logsharing/p/8036893.html

Linux下怎么查看进程,查看进程的运行目录

ps -aux | grep 搜索进程名 ,进入/proc/进程号/environ PWD字段

介绍一下这个项目

项目目的:
主要时当初看完APUE,UNP的时候觉得知识点很多很混乱,虽然了解到很多网络编程和系统编程的东西,网络编程这么多API哪些是常用的,但是感觉不会用,比如那么多中锁,我该如何选择,这么多通信方式我该选择哪种方式,并发模型该选择哪个,以及多线程编程中的优化操作该怎样去处理,也为了去巩固一些C++语法,比如bind,function,智能指针,然后就去选择写了这个网络库,这个网络库主要的作用就是向上层提供支持高并发,较为可靠网络通讯服务,使得编写服务端程序时可以把更多的精力放在业务层逻辑上

项目所用知识点:

采用epoll的IO复用,使用的时lt模式,这里提一句,在非阻塞中et并不见得比lt快,比如说在read的时候,假如应用层缓冲区的空间不够了,那么我们要等到空间足够时,把tcp缓冲区中的所有数据读完,这样无疑导致了效率的降低,然后使用了reactor模式,reactor模式是事件驱动模型,以事件作为驱动,根据不同事件做出不同的处理,主要包括,事件分发器,主线程,工作线程,注意是读完成事件,写完成事件,区别与practor模式
采用非阻塞IO,主要是为了防止出现某个线程阻塞在某个api上,从而导致无法响应其他请求

使用timefd和set去实现定时器功能,关于timefd的介绍,read返回超时的次数,使用timerfd的好处是可以将定时器和一般的fd同等对待,如果使用alarm的方式,处理信号在多线程中是个麻烦的事

双buffer异步日志系统,主要的实现是多个前端线程,和后端线程,前端只用将日志消息放进buffer中即可,后端线程将(为了将临界区缩短)buffermove到自己的buffer中,其中buffer的同步手段是条件变量,定时notify或者当有数据写入第一个buffer时唤醒,为了避免写入磁盘速度过慢使得线程阻塞,统一用后端进程写入

采用one loop per thread 并发模式,是指有多个reactor,有多个事件分发器,每一个线程控制一个epoll,由一个主IO线程负责将新的链接分发给其他的IO线程,也就是子reactor,之后由这个IO线程负责链接的读写事件的处理,关闭等等
好处是,可以有效避免突发IO的情况,突然有大量数据过来,如果使用单rector模式,则读写需要耗费大量时间,会使得其他请求得不到响应,采用多reactor的方法能简单的做出负载均衡,而且还可以根据不同优先级的链接交给不同的reactor来处理

RAII手法是指初始化即资源的获取,析构则是资源的释放,使用这种方式能有效避免忘记delete的情况,智能指针更是如此,主要使用shared_ptr和weak_ptr结合使用,weak_ptr主要用来反正延长对象周期

剩下就是测压问题(很重要)

无锁队列:

https://blog.csdn.net/weixin_40825228/article/details/80801596
利用CAS的乐观锁等手段,实现无锁队列,
进队操作
do{
while(rear->next!=null) rear = rear->next;
tmp = rear->next;
}while(!CAS(tmp->next,null,new node));

出队操作
do{
p = head;
while(!CAS(p,head,head->next);

CAS缺点: 可能出现ABA的问题(可以用循环队列解决)
当条件很长时间不满足时,自旋消耗cpu资源

EventFD实现线程唤醒
https://cloud.tencent.com/developer/article/1171508
eventfd的优点在于针对通知机制时,比pipe所带来的巨大优势
pipe消耗更多的文件描述符,每个pipe消耗内核缓冲区4k,而eventfd仅仅消耗一个8字节整数

日志系统的压力测试(重要)

获取Linux 内存页(基页)大小的命令:getconf PAGE_SIZE ,一般的输出是4096,即 4KB。

伙伴系统:

https://blog.csdn.net/csdn_kou/article/details/82355452

考虑申请(分割)和释放(合并)过程,用来处理外碎片
但是会产生内碎片

slab机制

主要用来解决内碎片,原理类似存储池,以slab为单位
有一个cache_lian,每一个节点对应三个链表,每个链表里是slab

epoll 源码

使用红黑树和就绪链表实现,使用slab机制分配内存,效率很高,不用每次都穿所有fd给内核,每次epoll_wait 只传就绪的列表,注意不适用共享内存
https://www.nowcoder.com/discuss/26226

epoll 的边沿触发和水平触发有什么区别

https://www.nowcoder.com/discuss/26226

从源码角度上回答就是再epoll返回数据给内核的时候就绪队列
中的就绪事件会被拷贝到一个中间列表,然后返回给用户态,
返回的时候判断是不是ET模式,如果是则不重新插回就绪链表中,否则重新插回就绪链表中,会在返回数据给用户态的时候重新获取一遍事件

HTTP报文

https://www.cnblogs.com/klguang/p/4618526.html

一个请求到来具体的处理过程是怎样的

首先当是一个新的链接时,主reactor也是主IO线程,accpet到一个新的链接后,触发新链接到来是的回调,会new出来一个TCPconnection,然后注册相应的读完成回调,写完成回调等等,然后主IO线程用round robin的方式从子reactor中选出一个,将函数指针丢进子reactor中任务队列,并且唤醒改子reactor,子IO线程执行该回调,注册读事件,然后该子IO线程就负责这个链接的读写
写过程:业务层向某个链接写数据,调用TCPconnection的send方法,先判断当前是否注册了写事件,如果没有注册,直接调用write,如果有数据剩余,存进写缓存区中,并且向epoll中注册写事件,等到下次触发写事件,如果已经注册了写事件那么,这直接添加到缓冲区中,等待写事件触发

读过程:过程比较简单,但是这里用了个用法,防止当前的读缓冲区空间不够,read是可能造成内存溢出的问题,我们每次读的时候用一个足够大的局部对象数组,然后用readv读进这两个位置,然后调用相应的回调

检查内存泄露工具:

使用valgrind

用法 valgrind --tool=memcheck --show-reachable=yes -tace-child=yes --leak-check=full
–tool 指定工具名
show-reachable 制定内存泄漏地点
trace-child跟随子进程,–leak-check = full 指的是完全检查内存泄漏

线程的唤醒方式

eventfd,pipe,条件变量,信号等

为什么要用非阻塞io

防止处理某一个事件时,阻塞再某一个系统调用上,导致其他请求等不到回应

压测(重要):

待填

死锁

死锁条件:
1 竞争有限资源
2 请求并占有
3 循环等待
4 不可抢占

死锁解决方案:
分三个阶段解决

1 死锁预防
通过一些预定的规则来打破死锁的必要条件
1 打破不可占有条件,当申请资源无法满足时,释放已占有的资源
2 打破请求并占有条件,申请资源时,一次性申请所有资源
3 打破循环等待,按照统一的顺序去申请资源

2 死锁避免
这一步时判断某个进程申请资源时,动态检查是否会出现死锁,主要用银行家算法

银行家算法:

https://blog.csdn.net/jgm20475/article/details/81265947

3 死锁检测和解除

死锁检测的时机:定时检测、效率低时检测、进程等待时检测
发生死锁时怎么恢复:直接重启,杀掉进程:全部杀,或者每次选择代价最小的杀,回退到没发生死锁的那一步

STL部分

空间配置器:

	http://luodw.cc/2015/10/26/Calloc/

分为一级配置器和二级配置器
一级配置器作用:用来针对请求分配大于128b的请求,内置用malloc和realloc来申请内存,malloc是分配一块新的内存
二realloc可以在已分配的内存的基础上扩大或者缩小

二级配置器:
当请求分配的内存小于128时,就会调用二级配置器,二级配置器大概是由一些链表数组组成的,按大小分组,分别是
8b,16b,24b,…128b,当请求申请空间时,先算出当前大小应该落在哪一个链表上,然后返回该链表的第一个节点,如果这个链表上没有可用的内存了,先从内存池中请求分配内存,默认是分配20个,如果内存池中也没有空闲的内存了,先回收内存池中剩余的内存,然后从系统中申请,如果系统中也无法满足的话,就从其他链表中获取空闲的内存,如果也没有就gg了,掉了第一级配置器的错误处理函数

空间配置器存在的问题
自由链表所挂区块都是8的整数倍,因此当我们需要非8倍数的区块,往往会导致浪费。

由于配置器的所有方法,成员都是静态的,那么他们就是存放在静态区。释放时机就是程序结束,这样子会导致自由链表一直占用内存,自己进程可以用,其他进程却用不了

vector释放内存

1 调用shrink_to_fit
2 利用swap

vectorfuck;
fuck.swap(Q);
Q = fuck;

迭代器:

五种迭代器类型:
1 只写迭代器,支持++,等操作
2 只读迭代器,支持 == ,!=,++,
,->等操作
3 Forward Iterator 向前迭代器,只支持单向移动,支持读写操作
4 双向迭代器,支持双向移动
5 随机访问迭代器,额外支持跳转多步的操作

仿函数

https://blog.csdn.net/Dawn_sf/article/details/70225382

简单而言即使重载类的()运算符,使得类具有函数的特征,可以和模板搭配使用
应用举例,shared_ptr时释放资源时,需要根据资源的不同使用到不同的释放方式,例如delete和delete[]
这个时候我们就用模板和仿函数搭配使用,写两个仿函数

适配器

就是使用另一种结构相似的结构来实现自己
容器适配器:提供了stack,queue,priority_queue
迭代器适配器: 插入迭代器,反向迭代器,流迭代器
函数适配器: 用来适配一元谓词,二元谓词等,但是都可以用bind来取代

容器

顺序容器,关联式容器

算法

sort,lower_bound, upper_bound等等

共享内存

https://blog.csdn.net/anzhsoft/article/details/18220683

主要就是mmap和shmopen,注意事项就是共享内存自己不提供同步手段,需要自己保证,还有就是当需要立马在文件中生效时,需要立马调用写进文件的api有异步和同步两种手法,

C++编译与链接

https://blog.csdn.net/u012411498/article/details/80843229

总的就是每个目标文件会有三个表,未解决符号表,导出符号表,地址重定向表

未解决符号表中储的就是本编译单元中没有申明定义的变量或者函数,导出符号表是本编译单元中提供给外界符号

原始套接字

https://blog.csdn.net/xiongwenwu/article/details/53089085

用来接受IP层和链路层的数据

linux的内存布局以及内核栈,进程栈,线程栈,中断栈

https://www.cnblogs.com/sky-heaven/p/7112006.html

内存对齐得原理和好处:

https://blog.csdn.net/liu1064782986/article/details/7612342

最小内存访问粒度,减小访问次数

守护进程

https://blog.csdn.net/QEcode/article/details/93667852

可变长结构体

https://blog.csdn.net/laoyang360/article/details/11908731

epoll的几种事件

https://blog.csdn.net/q576709166/article/details/8649911

sbrk和mmap的区别

https://blog.csdn.net/gfgdsg/article/details/42709943

C语言实现多态,封装,继承

https://zhuanlan.zhihu.com/p/25127633
https://zhuanlan.zhihu.com/p/25536183

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值