八股2
除了brk+mmap,malloc还有以下实现方式:
- sbrk:sbrk是brk的一个变体,它可以增加或减少进程数据段的大小。与brk不同的是,sbrk只能增加或减少数据段的大小,而不能直接设置数据段的大小。
- mmap:mmap可以将一个文件或者一个匿名映射区映射到进程的地址空间中。通过mmap可以在进程的地址空间中创建一个新的映射区,这个映射区可以用来存储malloc分配的内存。
- buddy算法:buddy算法是一种内存分配算法,它将内存分成大小相等的块,并将这些块组织成一棵二叉树。每个节点表示一个内存块,节点的左右子节点表示该内存块被分成的两个子块。当需要分配内存时,buddy算法会在二叉树中找到一个大小合适的内存块,并将其分配出去。
- slab分配器:slab分配器是一种内存分配器,它将内存分成大小相等的块,并将这些块组织成一个或多个slab。每个slab包含若干个大小相等的内存块,slab分配器会根据需要从slab中分配内存块,并在内存块不再使用时将其返回给slab。
Page cache(页缓存)是操作系统中的一种内存区域,用于缓存磁盘上的文件数据。它与一般的内存区域(如用户空间和内核空间)有以下区别:
- 功能:Page cache主要用于提高文件系统的性能,通过将磁盘上的文件数据缓存在内存中,减少对磁盘的读写操作,从而加快文件的访问速度。而一般的内存区域用于存储程序的代码和数据,以及操作系统的内核数据结构。
- 分配方式:Page cache的内存是通过文件系统缓存管理机制分配的,它是按需分配的,根据文件的访问情况动态调整大小。而一般的内存区域是通过操作系统的内存管理机制分配的,通常在程序启动时就会分配一定的内存空间。
- 内存回收:Page cache的内存可以被操作系统回收,以便为其他进程或文件提供更多的缓存空间。而一般的内存区域通常只有在进程退出或被操作系统终止时才会被释放。
分界的方式通常是通过操作系统的虚拟内存管理机制来实现的。操作系统将整个内存空间划分为多个页(通常是4KB大小),每个页可以被分配给不同的内存区域,包括Page cache和一般的内存区域。操作系统根据需要将文件数据加载到Page cache中,并根据访问模式进行缓存管理。当需要访问文件数据时,操作系统首先检查Page cache中是否存在相应的数据,如果存在则直接返回,否则从磁盘读取数据并将其缓存到Page cache中。
智能指针是一种用于管理动态内存的工具,它可以自动化内存的分配和释放,从而减少程序员手动管理内存的出错可能性。然而,智能指针也有一些缺点,包括以下几点:
1.性能开销:智能指针需要进行额外的内存管理和引用计数操作,这可能会导致程序的性能下降。相比于原始指针,智能指针需要更多的计算资源和时间来完成内存管理任务。
2.循环引用:如果智能指针被用于管理对象之间的循环引用,就可能会出现内存泄漏的问题。当两个对象相互引用时,它们的引用计数永远不会达到零,因此它们的内存也永远不会被释放。
3.难以调试:由于智能指针管理的内存是自动分配和释放的,因此在程序运行时,很难确定哪个指针指向哪个内存块,以及哪个指针可能导致内存泄漏或悬挂指针等问题。这使得调试非常困难。
4.不适用于某些场景:智能指针通常适用于单线程环境,但在某些多线程或异步环境中,智能指针的使用可能会导致竞态条件或死锁等问题。此外,智能指针也不适用于需要在不同的进程之间共享内存的场景。
erase"和"remove"都是用于删除容器中的元素的函数,但它们的实现方式和使用场景略有不同。"erase"是一个成员函数,用于从容器中删除指定位置的元素或指定范围内的元素。例如,可以使用vector的erase函数删除指定位置的元素:
std::vector<int> vec = {1, 2, 3, 4, 5}; vec.erase(vec.begin() + 2); // 删除第三个元素,即3
"remove"是一个算法函数,用于从容器中删除指定值的元素。例如,可以使用vector的erase和remove函数删除所有值为3的元素:
std::vector<int> vec = {1, 2, 3, 4, 5}; vec.erase(std::remove(vec.begin(), vec.end(), 3), vec.end()); // 删除所有值为3的元素
需要注意的是,remove函数并不会真正删除元素,而是将所有需要删除的元素移到容器的末尾,并返回一个指向新的末尾的迭代器。因此,需要再使用erase函数将这些元素真正删除。
vector与deque不同,其内存占用空间只会增长,不会减小。比如你首先分配了10,000个字节,然后erase掉后面9,999个,则虽然有效元素只有一个,但是内存占用仍为10,000个。所有空间在vector析构时回收。
empty()是用来检测容器是否为空的,clear()可以清空所有元素。但是即使clear(),所占用的内存空间依然如故。如果你需要空间动态缩小,可以考虑使用deque。如果非要用vector,这里有一个办法:
在《effective STL》和其实很多C++文章中都有指明,用clear()无法保证内存回收。但是swap技法可以。具体方法如下所示:vector<int> nums;nums.push_back(1);nums.push_back(1);nums.push_back(2);nums.push_back(2);vector<int>().swap(nums); //或者nums.swap(vector<int>());
oracle和mysql的区别:规模、费用、权限管理、表空间、自动提交(事务)、性能、稳定性、扩展性、是否支持全外连接、性能诊断工具
SQL加锁规则:原则 1:加锁的基本单位是 next-key lock。next-key lock 是前开后闭区间。原则 2:查找过程中访问到的对象才会加锁。优化 1:索引上的等值查询,给唯一索引加锁的时候,next-key lock 退化为行锁。优化 2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock 退化为间隙锁。一个 bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。加何种锁与where条件的字段是否有索引以及是否是唯一索引以及where条件的数据是否存在有关,比如:
在 update 语句的 where 条件使用了唯一索引,那么 next-key 锁会退化成记录锁,也就是只会给一行记录加锁。在 update 语句的 where 条件没有使用索引,就会对所有记录和间隙加上 next-key 锁(记录锁 + 间隙锁),相当于把整个表锁住了。
总之,非唯一索引就会加next key 锁
redis的线程模型:所以,Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行,也就不存在并发安全问题。
TCP长连接:本来就是HTTP长连接:就是keepalive,不断开TCPTCP keepalive:一段时间没有消息自动关闭
HTTP/2.0:
- 采用二进制协议,而不是HTTP/1.x的文本协议,可以更快地传输数据。
- 支持多路复用,可以在一个连接上同时发送多个请求和响应,减少了延迟和网络拥塞。
- 强制使用加密传输,提高了安全性。
- 支持服务器推送,可以在客户端请求之前主动向客户端发送资源,提高了性能。
HTTP/3.0:
- 采用QUIC协议,而不是TCP协议,可以更快地建立连接和传输数据。
- 支持多路复用和服务器推送,与HTTP/2.0类似。
- 支持0-RTT连接,可以在第一次连接时就发送数据,减少了延迟。
- 支持快速恢复,可以在网络中断后更快地恢复连接。
虚函数能内联吗:一般人肯定说不能用对象调用可以内联,用基类指针调用不能内联
HTTP包格式:请求行:请求方法。URI。协议版本消息头:
- Accept:指定客户端能够接收的内容类型。
- Accept-Charset:指定客户端能够接收的字符集。
- Accept-Encoding:指定客户端能够接收的内容编码。
- Accept-Language:指定客户端能够接收的自然语言。
- Authorization:包含客户端提供的认证证书,用于访问受密码保护的资源
- Cache-Control:指定请求/响应链上所有缓存机制必须服从的指令。
- Connection:指定与连接相关的选项。
- Content-Length:指定请求体的长度。
- Content-Type:指定请求体的MIME类型。
- Cookie:包含客户端发送的Cookie
- Host:指定请求的服务器的域名和端口号。
- If-Modified-Since:指定只有在指定日期之后修改过的资源才会被返回。
- If-None-Match:指定只有在指定的ETag与服务器上对应资源的ETag不同时才会被返回。
- Referer:指定当前请求的来源页面。
- User-Agent:指定客户端使用的浏览器类型和版本号。 消息体
只有vector.deque.array.string 支持随机访问迭代器
线程共享的资源:文件描述符列表、进程空间、代码、全局数据、堆、共享库
数据库优化的方法:数据库逻辑结构的设计:是否满足第几范式查询语句是否高效、是否进行了全表扫描。查询加索引了吗、是否是二级索引、是否是聚簇索引:查看慢查询表,或者分库分表、负载均衡、主从数据库同步redis缓存:缓存预热。缓存雪崩、缓存击穿、缓存穿透,server层缓存,引擎层缓存并发事务优化:更换隔离级别硬件优化:合理配置硬件资源可以提高数据库性能。增加内存、优化磁盘读写速度、使用高性能的存储设备等都可以提高数据库的响应速度。数据库版本升级:注意考虑兼容性问题
主机上的最大连接数:1.端口号限制2.文件描述符限制:系统级。用户级。进程级3.线程并发过多:使用多路复用