目录
1.HTTP3.0
HTTP3.0(也称为QUIC)是下一代HTTP协议。相比于现有的HTTP/1.x和HTTP/2,HTTP3.0采用了全新的协议栈,具有以下特点:
1.基于UDP:HTTP3.0基于UDP而非TCP,因此可以避免TCP协议慢启动、拥塞控制等带来的延迟和性能问题。
2.无阻塞:HTTP3.0采用了无阻塞I/O模型,通过复用和预先推送数据来避免阻塞,从而降低了延迟和提高了吞吐率。
3.多路复用:HTTP3.0仍然支持多路复用,但是与HTTP/2不同的是,HTTP3.0在传输层实现了一个基于流的多路复用协议,并且对于同一个域名,只需要建立一次连接。
4.加密:HTTP3.0要求所有通信都必须使用TLS/SSL加密,这可以保证数据的安全性和隐私性。
5.快速恢复:HTTP3.0在连接中实现快速恢复机制,当连接中遇到数据包丢失等网络问题时,可以更快地恢复服务。
总的来说,HTTP3.0具有更好的性能和安全性能,能够更快地传输数据和提升用户体验。目前,HTTP3.0正在逐步被各大浏览器、服务器厂商和CDN厂商支持和部署。
2.类继承中父类和子类的内存布局
在类继承中,父类和子类都有自己的内存布局,且子类的内存布局包含了父类的内存布局。
通常,子类对象的内存布局如下:
-
首先是该子类自己的成员变量;
-
然后是从父类继承下来的成员变量;
-
最后是可能存在的虚函数表指针(Vtable Pointer)和虚基类指针(Virtual Base Class Pointer)。
其中,虚函数表指针和虚基类指针只在存在虚函数或者虚继承关系时才会存在。
例如,假设有一个父类A和一个子类B,B从A继承下来了一个成员变量和一个虚函数,那么B的内存布局如下:
+------------------------------+
| B 自己的成员变量 |
+------------------------------+
| A 继承下来的成员变量 |
+------------------------------+
| 虚函数表指针(可能存在) |
+------------------------------+
如果B还继承自另一个父类C,且C是一个虚基类,那么B的内存布局如下:
+------------------------------+
| B 自己的成员变量 |
+------------------------------+
| A 继承下来的成员变量 |
+------------------------------+
| 虚函数表指针(可能存在) |
+------------------------------+
| C 的虚基类指针(可能存在) |
+------------------------------+
需要注意的是,子类的成员变量并不一定按照定义的顺序出现在内存中,编译器可能会对成员变量进行优化和重新排列。这种优化会涉及到内存对齐和填充等操作,以保证内存的访问效率和正确性。
3.讲一讲虚拟内存空间
虚拟内存是一种计算机内存管理技术,它通过将硬盘空间作为扩展内存,实现了对物理内存的扩充。虚拟内存可以让程序获得比实际物理内存更大的访问空间,从而使得更多的程序能够运行在同一时间内,提高了计算机的利用率和效率。
每个进程在运行时都有自己的虚拟内存空间,它包括程序代码、数据、栈、堆等内容。在虚拟内存的概念中,每个进程看到的内存空间是独立的,它们可以使用相同的内存地址而不会互相干扰。
虚拟内存由操作系统控制,它将物理内存分成多个大小相等的页面(通常是4KB),每个页面都有一个唯一的页号。进程访问虚拟内存时,操作系统会将虚拟地址转换成物理地址,具体的过程如下:
-
确定虚拟地址对应的页面编号;
-
根据页面编号和进程中对应的页表将虚拟地址转换成物理地址;
-
如果所需的物理页面尚未被缓存到内存中,则操作系统需要将其从硬盘中读入物理内存中;
-
如果物理内存已满,则操作系统需要根据缓存算法将某些页面从内存中换出到硬盘中,以便为新页面腾出空间。
在使用虚拟内存时,需要注意以下几点:
-
由于操作系统会动态地将页面从硬盘加载到内存中,因此访问虚拟内存中的数据通常比直接访问物理内存要慢;
-
只有在使用虚拟内存的时候,程序才能使用比实际物理内存更大的内存空间,但是如果程序使用的内存空间超过了可用的虚拟内存空间,程序将崩溃;
-
程序可以在虚拟内存中使用大量的内存,但是实际物理内存的大小是有限的,因此需要合理地分配内存资源,避免资源耗尽。
总之,虚拟内存是一种非常实用的内存管理技术,它能够提供比实际物理内存更大的内存空间,并保证了多个进程之间的独立性和安全性。
4.C++左值和右值
在 C++ 中,表达式可以分为左值(Lvalue)和右值(Rvalue)两种。
- 左值:
左值是指在表达式求值后,能够产生一个可以被修改的、具有持久性的对象或变量。也就是说,左值可以出现在一个赋值语句的左边。例如:
int a = 1; // a 是一个左值,它是一个可以被修改的变量。
int b = a; // a 是一个左值,它可以出现在赋值语句的右边。
- 右值:
右值是指在表达式求值后,只能产生一个临时的、不能被修改的值。也就是说,右值不能出现在一个赋值语句的左边,只能出现在一个赋值语句的右边。例如:
int b = 1; // 1 是一个右值,它不能被赋值,但是可以被赋给一个左值。
int c = a + b; // a 和 b 是左值,a + b 是一个右值,可以用于初始化一个左值。
在 C++ 中,通常可以将左值看作是存储在内存中的某个对象或变量的名称,而右值则指的是某个临时的值或表达式。在一些特定的场合下,C++ 也会将右值转化为左值,例如使用引用类型作为函数参数或返回值时。但是在大多数情况下,左值和右值是有明显区别的。
5.线程池中线程数量如何设计
线程池中线程数量的设计应该考虑以下几个因素:
-
CPU 的核数:线程池中的线程数量最好不要超过 CPU 的核数,否则会造成线程上下文切换的开销增加,影响程序性能。通常可以通过
std::thread::hardware_concurrency()
函数获取机器上的 CPU 核数。 -
任务的类型和处理时间:如果线程池中的任务需要比较长的时间才能完成,那么线程池中的线程数量可以适当增加,以充分利用空闲的 CPU 时间,提高程序性能。但是如果线程池中的任务处理时间较短,线程池中的线程数量就需要较少,以免浪费系统资源。
-
系统资源的限制:线程池中的线程数量还需要考虑系统资源的限制,例如内存、磁盘等资源。
-
业务需求:线程池中的线程数量还需要根据具体的业务需求进行调整,例如不同的任务种类、不同的业务规模等。
综合以上几个因素,我们可以根据需求进行适当地调整线程池中的线程数量,以达到最优的性能和资源利用率。