面试题答案
一键面试动态调整文件描述符限制
- ulimit命令:在shell环境中,可以使用
ulimit -n [new_limit]
命令临时提高当前会话的文件描述符限制。例如,ulimit -n 10000
将文件描述符限制提高到10000。但这种方式只对当前会话有效,进程结束后设置失效。 - 修改系统配置文件:
- 在Linux系统中,编辑
/etc/security/limits.conf
文件。添加或修改如下行:
其中* soft nofile [new_soft_limit] * hard nofile [new_hard_limit]
*
表示对所有用户生效,soft
是软限制,hard
是硬限制。修改后需要重新登录或重启相关服务使配置生效。
- 在Linux系统中,编辑
- 程序中动态调整:在C程序中,可以使用
setrlimit
系统调用。示例代码如下:#include <sys/resource.h> #include <stdio.h> int main() { struct rlimit rlim; if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) { perror("getrlimit"); return 1; } rlim.rlim_cur = 10000; // 设置软限制 rlim.rlim_max = 10000; // 设置硬限制 if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) { perror("setrlimit"); return 1; } return 0; }
避免内存碎片问题
- 内存池技术:
- 预先分配一块较大的内存块作为内存池。当需要为I/O操作或连接管理分配内存时,从内存池中分配小块内存。使用完后,将小块内存归还给内存池,而不是直接调用
free
释放内存到系统堆。 - 例如,可以使用链表结构来管理内存池中的空闲块。当分配内存时,从链表中寻找合适大小的块;归还时,将块重新插入链表。
- 预先分配一块较大的内存块作为内存池。当需要为I/O操作或连接管理分配内存时,从内存池中分配小块内存。使用完后,将小块内存归还给内存池,而不是直接调用
- 固定大小分配:对于一些有固定大小需求的内存分配场景,如连接管理中的连接结构体,可以使用固定大小的内存分配策略。比如使用
malloc
分配一个较大的连续内存块,然后按照连接结构体的大小划分成多个小块,每个小块用于一个连接的管理。这样可以减少内存碎片的产生。 - 内存对齐:在定义结构体和分配内存时,注意内存对齐。合理的内存对齐可以提高内存访问效率,同时减少因内存对齐问题导致的内存浪费,间接减少内存碎片。例如,使用
#pragma pack
指令设置结构体的对齐方式。
优化多路复用实现及系统配置以提高性能
- 优化多路复用实现:
- epoll事件处理优化:
- 尽量减少在epoll事件回调函数中的复杂操作。例如,将数据处理逻辑放到单独的线程或进程中执行,epoll事件回调函数只负责将数据从内核缓冲区拷贝到用户空间,并将任务提交到处理队列。
- 合理设置epoll的触发模式。对于边缘触发(ET)模式,需要确保一次性读取或写入所有数据,避免数据残留导致的重复触发问题。
- 连接管理优化:
- 采用连接池技术,避免频繁的连接建立和关闭。预先创建一定数量的连接,放入连接池中,当有请求时从连接池中获取连接,使用完后归还。
- 对于长时间不活跃的连接,进行适当的清理和回收,以释放资源。
- epoll事件处理优化:
- 系统配置优化:
- 网络参数调整:
- 修改
/proc/sys/net/core/somaxconn
参数,增加监听队列的长度,避免因队列溢出导致的连接丢失。例如,echo 1024 > /proc/sys/net/core/somaxconn
将监听队列长度设置为1024。 - 调整
/proc/sys/net/ipv4/tcp_max_syn_backlog
参数,优化TCP三次握手过程中的半连接队列长度。
- 修改
- CPU亲和性设置:使用
taskset
命令或pthread_setaffinity_np
函数将进程或线程绑定到特定的CPU核心上,避免CPU上下文切换带来的开销,提高性能。例如,taskset -p 0x1 <pid>
将指定进程绑定到CPU 0。
- 网络参数调整: