ls cd mv cp touch mkdir mkfifo ln tailf du top iostat uptime df
netstat
显示网络状态
tcpdump
主要是截获通过本机网络接口的数据,用以分析
ipcs
检查系统上共享内存的分配
ipcrm
手动解除系统上共享内存的分配
查看CPU信息
#cat /proc/cpuinfo
查看内存信息
#cat /proc/meminfo
查看硬盘分区信息
使用下面的命令,可以看到当前硬盘的分区信息,以及容量大小、已使用的空间和剩余空间大小,还可以查看每个分区的挂载点:
#df -lh
查看进程状态
ps 命令
共享内存
是最快的可用IPC(进程间通信)形式。它允许多个不相关的进程去访问同一部分逻辑内存。共享内存是由IPC为一个进程创建的一个特殊的地址范围,它将出现在进程的地址空间中。其他进程可以把同一段共享内存段“连接到”它们自己的地址空间里去。
进程内存空间分布
注意栈从高到低分配,堆从低到高分配。
进程间通讯机制
http://blog.51cto.com/12880687/2095466
在多线程环境下,每个线程拥有一个栈和一个程序计数器。栈和程序计数器用来保存线程的执行历史和线程的执行状态,是线程私有的资源。其他的资源(比如堆、地址空间、全局变量)是由同一个进程内的多个线程共享。线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
所有 32 位应用程序都有 4 GB 的进程地址空间(32 位地址最多可以映射 4 GB 的内存
动态链接和静态链接
动态链接是指在生成可执行文件时不将所有程序用到的函数链接到一个文件,因为有许多函数在操作系统带的dll文件中,当程序运行时直接从操作系统中找。 而静态链接就是把所有用到的函数全部链接到exe文件中。
动态链接是只建立一个引用的接口,而真正的代码和数据存放在另外的可执行模块中,在运行时再装入;而静态链接是把所有的代码和数据都复制到本模块中,运行时就不再需要库了
如何定位内存泄露
内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的、大小任意的(内存块的大小可以在程序运行期决定)、使用完后必须显示释放的内存。应用程序一般使用malloc、realloc、new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块。否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。
C++程序缺乏相应的手段来检测内存信息,只能使用top指令观察进程的动态内存总额。而且程序退出时,我们无法获知任何内存泄漏信息。使用Linux命令回收内存,可以使用ps、kill两个命令检测内存使用情况和进行回收。在使用超级用户权限时使用命令“ps”,它会列出所有正在运行的程序名称和对应的进程号(PID)。kill命令的工作原理是向Linux操作系统的内核送出一个系统操作信号和程序的进程号(PID)。
如果是go 可以用性能分析攻击go tool pprof ,和gogctrace
常见信号
SIGSTOP暂停进程 、SIGKILL杀死进程
判断系统位数
0取反,然后判断大小
原码反码补码
原码就是二进制定点表示法,即最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。
反码表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
补码表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。
注意:计算机中只有 +0 而不存在 -0的说法,因为-0是完全没有意义的存在
守护进程
Daemon()程序是一直运行的服务端程序,又称为守护进程。通常在系统后台运行,没有控制终端,不与前台交互,Daemon程序一般作为系统服务使用,在系统关闭时才结束。
死锁的条件。(互斥条件(Mutual exclusion)
1、资源不能被共享,只能由一个进程使用。
2、请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。
3、非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。
4、循环等待条件(Circular wait):系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。
处理死锁的策略:
1.忽略该问题。例如鸵鸟算法,该算法可以应用在极少发生死锁的的情况下。为什么叫鸵鸟算法呢,因为传说中鸵鸟看到危险就把头埋在地底下,可能鸵鸟觉得看不到危险也就没危险了吧。跟掩耳盗铃有点像。
2.检测死锁并且恢复。
3.仔细地对资源进行动态分配,以避免死锁。
4.通过破除死锁四个必要条件之一,来防止死锁产生。
Epoll机制
阻塞I/O的缺点。但是阻塞I/O模式下,一个线程只能处理一个流的I/O事件。如果想要同时处理多个流,要么多进程(fork),要么多线程(pthread_create),很不幸这两种方法效率都不高。
epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll之会把哪个流发生了怎样的I/O事件通知我们。
阻塞模式下,内核对于I/O事件的处理是阻塞或者唤醒,而非阻塞模式下则把I/O事件交给其他对象(后文介绍的select以及epoll)处理。
select的缺点:
* 单个进程能够监视的文件描述符的数量存在最大限制,通常是1024,当然可以更改数量,但由于select采用轮询的方式扫描文件描述符,文件描述符数量越多,性能越差;(在linux内核头文件中,有这样的定义:#define __FD_SETSIZE 1024)
* 内核 / 用户空间内存拷贝问题,select需要复制大量的句柄数据结构,产生巨大的开销;
* select返回的是含有整个句柄的数组,应用程序需要遍历整个数组才能发现哪些句柄发生了事件;
* select的触发方式是水平触发,应用程序如果没有完成对一个已经就绪的文件描述符进行IO操作,那么之后每次select调用还是会将这些文件描述符通知进程。
相比select模型,poll使用链表保存文件描述符,因此没有了监视文件数量的限制,但其他三个缺点依然存在。
拿select模型为例,假设我们的服务器需要支持100万的并发连接,则在__FD_SETSIZE 为1024的情况下,则我们至少需要开辟1k个进程才能实现100万的并发连接。除了进程间上下文切换的时间消耗外,从内核/用户空间大量的无脑内存拷贝、数组轮询等,是系统难以承受的。因此,基于select模型的服务器程序,要达到10万级别的并发访问,是一个很难完成的任务。
因此,该epoll上场了。
由于epoll的实现机制与select/poll机制完全不同,上面所说的 select的缺点在epoll上不复存在。
设想一下如下场景:有100万个客户端同时与一个服务器进程保持着TCP连接。而每一时刻,通常只有几百上千个TCP连接是活跃的(事实上大部分场景都是这种情况)。如何实现这样的高并发?
epoll改进了select的两个缺点,使用了三个数据结构从而能够在管理大量的描述符的情况下,对系统资源的使用并没有急剧的增加,而只是对内存的使用有所增加(毕竟存储大量的描述符的数据结构会占用大量内存)。
epoll在实现上的三个核心点是:1、mmap,2、红黑树,3、rdlist(就绪描述符链表)接下来一一解释这三个并且解释为什么会高效;
1、mmap是共享内存,用户进程和内核有一段地址(虚拟存储器地址)映射到了同一块物理地址上,这样当内核要对描述符上的事件进行检查的时候就不用来回的拷贝了。
2、红黑树是用来存储这些描述符的,因为红黑树的特性,就是良好的插入,查找,删除性能O(lgN)。
3. rdlist 就绪描述符链表这是一个双链表,epoll_wait()函数返回的也是这个就绪链表。
当内核创建了红黑树之后,同时也会建立一个双向链表rdlist,用于存储准备就绪的描述符,当调用epoll_wait的时候在timeout时间内,只是简单的去管理这个rdlist中是否有数据,如果没有则睡眠至超时,如果有数据则立即返回并将链表中的数据赋值到events数组中。这样就能够高效的管理就绪的描述符,而不用去轮询所有的描述符。
对与rdlist的维护:当执行epoll_ctl时除了把socket描述符放入到红黑树中之外,还会给内核中断处理程序注册一个回调函数,告诉内核,当这个描述符上有事件到达(或者说中断了)的时候就调用这个回调函数。这个回调函数的作用就是将描述符放入到rdlist中,所以当一个socket上的数据到达的时候内核就会把网卡上的数据复制到内核,然后把socket描述符插入就绪链表rdlist中。
epoll使用过程
创建socket // socket
设置非阻塞模式 //setnonblocking
将socket绑定ip //bind
监听指定端口 //listen
创建一个epoll的句柄 // epoll_create()
添加监听套接字 listenfd ,用电平触发模式来监听输入事件 // ev.events = EPOLLIN; ev.data.fd = listenfd; epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev)
外层的 while 循环是主要事件循环。它调用epoll_wait(2),线程保持阻塞以等待事件到来。当事件就绪,epoll_wait(2) 用 events 参数返回事件,这个参数是一群 epoll_event 结构体。当我们添加新的监听输入连接以及删除终止的现有连接时,efd 这个 epoll 实例在事件循环中不断更新。 //epoll_ctl()系统调用。通过此调用向epoll对象中添加、删除、修改感兴趣的事件,返回0标识成功,返回-1表示失败。
代码样例:http://blog.51cto.com/12880687/2119807
epoll有两个工作模式
ET模式是高速模式,叫做边缘触发模式。当工作在ET模式下,如果一个描述符上有数据到达,然后读取这个描述符上的数据如果没有将数据全部读完的话,当下次epoll_wait返回的时候这个描述符里的数据就再也读取不到了,因为这个描述符不会再次触发返回,也就没法去读取,所以对于这种模式下对一个描述符的数据的正确读取方式是用一个死循环一直读,读到么有数据可读的情况下才可以认为是读取结束。ET模式在物理实现上是基于电平的高低变化来工作的,就是从高电平变成低电平,或者从低电平变成高电平的这个上升沿或者下降沿才会触发,也就是状态变化导致触发,而当一个描述符上数据未读完的时候这个状态是不会发生变化的,所以触发不了,LT模式是在只有出现高电平的时候才会触发。
LT模式是默认模式,叫做水平触发模式。工作在LT模式下,如果对一个描述符的数据没有读取完成,那么下次当epoll_wait返回的时候会继续触发,也就可以继续获取到这个描述符,从而能够接着读。
大端小端
小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
大端模式 :符号位的判定固定为第一个字节,容易判断正负。
之所以有大小端是因为不同类型的处理器有8位、16位、32位、64位,存储存在排序问题,有些处理器同时支持大端和小端
网络序和主机序
网络字节序是确定的,而主机字节序的多样性往往是混淆的原因。网络传输一般采用大端序,也被称之为网络字节序,或网络序,即先发送高字节数据再发送低字节数据(如:四个字节由高位向低位用0-31标示后,将首先发送0-7位第一字节,在发送8-15第二字节,以此下去)。IP协议中定义大端为网络字节序。
判断机器CPU位数
直接打印出指针占多少字节,4字节为32位系统,8字节为64位系统。
判断机器大小端
采用union判断,union的成员都是从低地址开始存放:
union U{
short a;
char b;
};
UNIX环境编程
UNIX常见命令
文件操作
进程编程
线程编程
进程间通信
硬链接和源文件是同一份文件,而软连接是独立的文件
项目中遇到的难点?
项目有什么改进的地方?
测试用例基本为0,测试用例,覆盖
回答说是快排,然后时间复杂度平均 O(nlogn),最差O(n2 )。实现的话就是一个 partition 和递归快速排序。
列举说明linux系统的各类异步机制
makefile
gdb调试
2, 从socket读数据时,socket缓存里的数据,可能超过用户缓存的长度,如何处理? 例如,socket缓存有8kB的数据,而你的缓存只有2kB空间。
3, 向socket发送数据时, 可能只发送了用户缓存里的一半,如何处理?例如,需要向socket发送8kB数据,返回值只有2kB发送成功。
13, TCP的三次握手, TIME_WAIT和CLOSE_WAIT状态是什么?
2, 从socket读数据时,socket缓存里的数据,可能超过用户缓存的长度,如果处理?
可以调用realloc(),扩大原有的缓存块尺寸。
但是临时申请内存的有一定性能损失。
这种情况要看接收缓存的方式。
第一种方式: 使用100k的大接收缓存为例。
如果要等待数据,并进行解析。可能发生缓存不够的情况。此时只能扩充缓存,或先处理100k的数据,再接收新的数据。
第二种方式: 使用缓存队列,分成8K大小的队列。
不存在接收缓存不够的情况。 除非用户解析已出错,使用数据接收、使用脱勾。 这种方式的代价是,可能需要将缓存队列再次拷贝、拼接成一块大的缓存,再进行解析。 而在本人的系统中,只需要将socket接收的数据再次原样分发给客户, 所以这种方案是最佳方案。
6, 非阻塞connect()如何实现?
将socket设置成non-blocking,操作方法同非阻塞read()、write();
网友评论