有几个 问题还是需要细琢磨的,记录下来。
1、构造函数中抛异常和析构函数抛异常会有问题吗?
构造函数中抛异常,会导致析构函数不会被调用;无法调用析构函数可能会导致能会造成内存泄露或系统资源未被释放。所以构造函数可以抛异常的前提是抛异常之后,及时释放系统资源。
C++标准指明不允许在析构函数中抛异常。1)如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。2)c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。(异常套异常,程序崩溃)
2、C++ new 数组obj[],如果只delete obj而不采用delete []obj,这样做可以吗?为什么。
如果数组内元素是基本内置类型,是可以的但是不建议这么做;但是如果是非内置数据类型比如是自定义类,则不可以的。因为delete 只调用了首元素的类型的析构函数,其他元素的析构函数没有调用到,导致内存泄漏。
3、C++11中enable_shared_from_this的用法解析
std::enable_shared_from_this 能让其一个对象(假设其名为 t ,且已被一个 std::shared_ptr 对象 pt 管理)安全地生成其他额外的 std::shared_ptr 实例(假设名为 pt1, pt2, … ),它们与 pt 共享对象 t 的所有权。
例如:若一个类 T 继承自 std::enable_shared_from_this<T> ,则 T 类中有继承自父类的成员函数: shared_from_this 。 当 T 类的对象 t 被一个为名为 pt 的 std::shared_ptr 类对象管理时,调用 T::shared_from_this 成员函数,将会返回一个新的 std::shared_ptr 对象,它与 pt 共享 t 的所有权。
4、为什么要用 enable_shared_from_this?
需要在类对象的内部中获得一个指向当前对象的 shared_ptr 对象。
如果在一个程序中,对象内存的生命周期全部由智能指针来管理。在这种情况下,要在一个类的成员函数中,对外部返回 this 指针就成了一个很棘手的问题。
参考连接:
C++11标准库的一个工具类enable_shared_from_this<T>的作用及原理分析 - joeyzzz - 博客园 (cnblogs.com)
5、线程创建的开销
对操作系统来说,创建一个线程的代价是十分昂贵的, 需要给它分配内存、列入调度,同时在线程切换的时候还要执行内存换页,CPU 的缓存被清空,切换回来的时候还要重新从内存中读取信息,破坏了数据的局部性。【分配内存、列入调度、内存换页、清空缓存和重新读取】
6、减少上下文切换的方法:
1)无锁并发编程:
多线程竞争锁时,会引起上下文切换,所以在使用多线程处理数据时,可以采用一些策略来避免使用锁。常见的策略:将数据按照id的哈希值进行切分,不同的线程处理不同段的数据。
2)锁分离技术:
举例:ConcurrentHashMap
3)CAS算法
4)使用最少的线程
避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。
5,6属于多线程的开销;
7、锁的开销
锁开销优化以及 CAS 简单说明 - cposture - 博客园 (cnblogs.com)
8、std::unodered_map 提高查询效率
1、insert/clear优化,当插入操作过多时,发生哈希碰撞的概率会非常大,碰撞开链,会触发新增bucket继而触发rehash。可以预先通过reserve可以预留元素个数,根据提供的元素个数预留足够的bucket数目;
2、unordered_map 每清空一次会遍历删除所有内容,替换为swap。
9、TCP的keepalive机制(长连接机制)
TCP keepAlive含义:在TCP中有一个Keep-alive的机制可以检测死连接,原理很简单,TCP会在空闲了一定时间后发送数据给对方:
1.如果主机可达,对方就会响应ACK应答,就认为是存活的。
2.如果可达,但应用程序退出,对方就发RST应答,发送TCP撤消连接。
3.如果可达,但应用程序崩溃,对方就发FIN消息
4.如果对方主机不响应ack, rst,继续发送直到超时,就撤消连接。这个时间就是默认的二个小时。
10、TCP的 Nagle算法
现实中,数据传输场景基本分为批量数据和交互式数据两种,批量数据一般是文件传输等,交互式一般和用户实时交互相关的,比如SSH。交互式传输特点,数据包较小。 试想一帧TCP报文中头部占用了(14+20+20) 54字节,你如果一帧传输1个字节应用数据,你觉得合适吗?一帧TCP报文最大携带1460字节载荷,车没装满就出发了?
Nagle算法用于减少TCP小包的发送,提高TCP报文有效载荷占比,来降低流量;保证时效性的情况下,尽量在车装满的情况下再发车。
Nagle算法要求:当一个TCP连接中有在传数据(即那些已发送但还未收到ACK确认的数据),小的报文段(长度小于SMSS)就不能发送,直到所有的在传数据都收到ACK确认;并且需要TCP重新组包将小数据整合成大包发送。很显然,对端ACK响应越快,数据传输也越快,也就是RTT控制着发包速率。 该算法使得单位时间内发送的报文段个数减少,也提高了TCP报文有效载荷占比,降低流量。
11、进程,线程,协程
程序是一些保存在磁盘上的指令的有序集合,是静态的。进程是程序执行的过程,包括了动态创建、调度和消亡的整个过程,进程是程序资源管理的最小单位。
线程是操作操作系统能够进行运算调度的最小单位。线程被包含在进程之中,是进程中的实际运作单位,一个进程内可以包含多个线程,线程是资源调度的最小单位。
线程资源和开销
同一进程中的多条线程共享该进程中的全部系统资源,如虚拟地址空间,文件描述符文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈、寄存器环境、线程本地存储等信息。
线程创建的开销主要是线程堆栈的建立,分配内存的开销。这些开销并不大,最大的开销发生在线程上下文切换的时候。
协程(coroutine)是一种程序运行的方式,即在单线程里多个函数并发地执行.
A coroutine is a function that can suspend its execution (yield) until the given given YieldInstruction finishes.
在协程中的函数, 如果执行过程中遇到了I/O密集型任务, 被给定的YieldInstruction
(让出指令)暂停执行(yield), 交出执行权到其他函数, 直到被给定的YieldInstruction
(让出指令)结束, 再继续.