day15(内存泄漏、段错误、malloc与new、API、reacter、单线程高并发、进程通信、线程通信)
- 内存泄漏通常是由new/malloc申请内存后,缺少对应的delete/free。
判断内存是否泄漏,一方面使用linux环境下的内存泄漏检查工具Valgrind
另一方面可以添加内存申请和释放的统计功能,统计当前内存申请和释放是否一致,判断内存是否泄漏。 - 段错误是发生在访问非法内存地址时,一是使用野指针,二是试图修改字符串常量。
野指针
定义:指针定义时未被初始化,指定在定义时,如果程序不对其进行初始化的话,它会指向随机区域。
导致野指针:
引用未初始化的指针变量。
引用被赋值为NULL的指针变量
free指针后未把指针置NULL
规避方法:
初始化指针时将其置为NULL,之后再对其进行操作。
释放指针时将其置NULL,最好在编写代码时把free函数封装一下,每次free后都置指针为NULL。 - 内存泄漏,memory leak,分类:
堆内存泄漏,Heap leak。程序运行时,通过malloc、new、realloc等从堆中分配内存时,完成后缺少了对应的delete/free,导致内存未被释放,那么之后这块内存想不会再使用,造成了堆泄漏。
系统资源泄漏,Resource leak。主要指程序使用系分配的资源,如:Bitmap、handle、SOCKET等没有使用对应的函数进行释放,就会浪费资源,严重的会影响系统效能降低,运行不稳定。
没有将基类的析构函数定义为虚函数,当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用,子类的资源也就不会被释放,造成内存泄漏。 - malloc和new的区别
new是按数据类型进行分配,malloc是按照指定大小。
new不仅分配一段内存,而且还会调用构造函数,malloc不会。
new分配的内存要用delete销毁,malloc要用free来销毁;delete销毁时会调用对象的析构函数,free不会。
new是一个操作符可以重载,malloc是一个库函数。
malloc分配的内存不够的话,可以用realloc扩容,new没有这个操作。
申请数组时,new[]一次分配所有的内存,多次调用构造函数,搭配delete,delete是多次调用析构函数,而malloc只能sizeof(int)*n。
malloc是在堆中分配内存,new自由存储区 - API,应用程序接口。
共享内存相关的api,Linux允许不同进程访问同一个逻辑进程,提供了一组API,头文件在sys/shm.h中。 - reacter模型组成
reactor模型要求主线程只负责监听文件描述上是否有事件发生,有就立即将该事件通知工作线程,除此之外主线程不做其他工作。 - 如何采用单线程的方式处理高并发。
在单线程模型中,可以采用I/O复用来提高单线程处理多个请求的能力,然后再采用事件驱动模型,基于异步回调来处理事件。 - Lambda表达式定义了一个匿名函数,并且可以捕获一定范围的变量。
- 进程间的通信主要是 管道、系统IPC(消息队列、信号量、信号、共享内存)、以及套接字socket。
管道包括无名管道和命名管道:管道可以用于具有亲缘关系的父子进程间的通信,有名管道除了具有管道的的功能外,还可以允许无亲缘关系的进程通信。
普通管道PIPE,命名管道FIFO
消息队列,是消息的链接表,存放在内存,一个消息队列由一个标识符(队列ID)来标记。
消息队列克服了信号传递 信息少,管道只能承载无格式数据流和缓冲区大小受限的特点。
特点:
面向记录的,具有特定的格式和特定的优先级。
消息队列独立于发送和接受进程,进程终止时消息队列及其内容并不会删除。
消息队列可以实现消息的随机查询,不一定要先进先出,可以按消息的类型读取。
信号量(semaphore),他是一个计数器,用来控制多个进程对共享资源的访问。信号量用 实现进程间的互斥和同步,而不是用于存储进程间的通信数据。
特点:
用于进程间的同步,若要在进程间传递时就需要结合共享内存。
信号量基于系统的PV操作,程序对信号量的操作都是原子操作(就是最小执行单位,不会被其他任何事件打断)。
支持信号量组,且每次操作不一定是加一减一,也可以是任意整数。
信号:是一种比较复杂的通信方式,用于通知接受进程某个事件已经发生。
共享内存,可以使多个进程访问同一块内存,不同进程可以及时看到对方进程对共享内存的 数据更新,这种方式需要依靠某种同步操作,如互斥锁、信号量等。
特点:
是最快的一种IPC,因为进程直接对内存存取。
因为多个进程可以同时操作,所以需要进行同步。
信号量+共享内存通常结合起来使用。信号量用来同步对共享内存的访问。
套接字socket,也是进程间通信的机制,与其他不同的是,可以用于不同主机之前的进程通信。 - 线程间的通信(线程同步)
临界区,通过多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。
互斥量,采用互斥对象机制,只有拥有互斥对象的线程才可以访问公共资源。因为互斥对象那个只有一个,所以可以保证公共资源不被多个线程同时访问。
信号量,为控制具有有限数量的用户资源设计,它允许多个线程在同一时间访问同一个资源,但是要限制同一时刻的最大线程数目。
事件(信号),通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。
怎么实现多线程安全
- 通过原子指令,每个线程运行就不能被打断
- 线程同步与锁,通过临界区、互斥量、信号量、信号实现同步,或者用互斥锁、读写锁