1、内存泄露:内存泄露一般是指动态创建的内存由于没有释放或者程序中出现异常而没有释放。内存泄漏通常不会直接产生可观察的错误症状,而是逐渐积累,降低系统整体性能,极端的情况下可能使系统崩溃。
(1)检测内存泄露:
ElectricFence函数库它使用虚拟内存机制来保护malloc和free所使用的内存,当发现内存被破坏时就停止运行。
Vld库
(2)预防内存泄露
利用智能指针:C/C++语言没有自动内存回收机制,程序员每次new出来的内存都要手动delete。可以使用智能指针的方式来解决内存泄露。
智能指针:对于编译器来说智能指针实际上就是一个栈对象,在栈对象的生命周期结束时,就会调用该对象的析构函数释放它所管理的堆内存。智能指针重载了指向运算符。可以通过get()得到智能指针包含的裸指针,可以用reset()释放当前管理的内存。
在boost库中包含以下几种智能指针:
std::auto_ptr
boost::scoped_ptr:独享所有权
boost::shared_ptr:引入了引用计数
boost::scoped_array:管理动态数组的
boost::shared_array:管理动态数组
boost::weak_ptr:专门为了share_ptr设计的,是share_ptr的观察者,不会增加引用计数,防止了智能指针交叉引用,share_ptr失效,weak_ptr也会随之失效。
boost:: intrusive_ptr
2、堆和栈的区别
在虚拟地址空间中,堆是向上增长的,栈是向下增长的。
(1)栈主要用来函数调用。栈用来保存函数返回地址和参数、临时变量(包括局部变量和编译器自动生成的临时变量)、函数上下文(如一些寄存器中的值)栈帧的开辟和回退是系统决定的。
(2)栈在函数调用返回后就释放了,无法将它带出,全局变量在编译的时候就确定了,无法动态产生。堆却可以动态的分配,并在程序主动释放前不会被释放。
(3)堆的分配和释放其实是由运行库来管理的(如c语言库),运行库首先向操作系统批发一块大的地址空间,然后零售给程序使用。运行需要一套堆分配算法,来管理堆。运行库向liunx系统批发一块大的地址空间时,调用linux系统调用brk()或者mmap()函数。
3、tcp协议的timewait状态和closewait状态
closewait状态是在服务器服务发送ack之后,在被动关闭之前,所以不会存在大量处于closewait状态 的端口,timewait状态是客户端发送确认后进入timewait状态,经过2MSL等待状态。TCP允许不同的试下根据具体情况使用更小的MSL值,当客户端撤销了传输控制块TCB后,才会结束这次的TCP连接。
缩小MSL值:可以设置SOCK_REUSEADDR选项,可以使处于2MSL状态的端口重用,但是不建议使用。
4、select poll epoll
epoll高效,是因为内部用了一个红黑树记录添加的socket,用了一个双向链表接收内核触发的事件。是系统级别的支持的:
当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体,这个结构体中有两个成员与epoll的使用方式密切相关。
eventpoll结构体如下所示:
struct eventpoll{
....
/*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件
struct rb_root rbr;
/*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/
struct list_head rdlist;
....
};
每一个epoll对象都有一个独立的eventpoll结构体,用于存放通过epoll_ctl方法向epoll对象中添加进来的事件。这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是lgn,其中n为树的高度)。而所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当相应的事件发生时会调用这个回调方法。这个回调方法在内核中叫ep_poll_callback,它会将发生的事件添加到rdlist双链表中。
在epoll中,对于每一个事件,都会建立一个epitem结构体,如下所示:
struct epitem{
struct rb_node rbn;//红黑树节点
struct list_head rdllink;//双向链表节点
struct epoll_filefd ffd; //事件句柄信息
struct eventpoll *ep; //指向其所属的eventpoll对象
struct epoll_event event; //期待发生的事件类型
}
为什么epoll比select和poll更高效
(1)不用重复传递。我们调用epoll_wait时就相当于以往调用select/poll,但是这时却不用传递socket句柄给内核,因为内核已经在epoll_ctl中拿到了要监控的句柄列表。
(2)这是由于我们在调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。所以,epoll_wait非常高效。
5、进程间通信 (消息队列、管道、共享内存、socket、信号量)
(1)共享内存实现原理:创建一块内存区域映射到进程的虚拟地址空间(虚拟地址空间的地址是可以不同的)。
(2)用socket进行进程间本地通信要经过网卡吗?不经过。一个本地进程为另一个本地进程产生的, 它们将通过外出链的'lo'接口,然后返回进入链的'lo'接口,而lo接口是不经过网卡的。