Libevent 虽然强大,但也很容易误用。以下是社区中最高频的“踩坑”记录。
1. 多线程噩梦
1.1. 忘记初始化锁
现象: 程序随机 Crash,GDB 堆栈指向
event_add 或链表操作。 原因:
多线程环境下未调用 evthread_use_pthreads()。
解决: 在 main
函数第一行调用它。
1.2. 回调“自杀”
现象: 在 bufferevent
的回调函数中调用 bufferevent_free(bev),导致
Use-after-free 或死锁。 原因: Libevent
内部可能还在使用这个 bev 对象。 解决: 使用
BEV_OPT_DEFER_CALLBACKS 选项创建
bufferevent,或者确保 free 后立即返回,不再触碰 bev。
2. 内存与缓冲
2.1. OOM (内存溢出)
现象: 内存占用持续飙升,最终被 OOM
Killer 杀掉。 原因: 接收速度 >
处理速度,且未设置高水位。input buffer
无限膨胀。 解决: 务必设置
bufferevent_setwatermark(bev, EV_READ, 0, 1024*1024)。
3. 进程模型
3.1. Fork 后失效
现象: fork
后子进程的事件循环没反应,或者报错。 原因:
epoll fd 不能跨进程共享。 解决:
子进程必须调用 event_reinit(base)。
4. 隐蔽的阻塞
4.1. DNS 查询
现象: 偶尔整个服务卡顿几秒。
原因: 在回调中使用了
gethostbyname 或 mysql_connect
等阻塞函数。 解决: 使用 evdns
或线程池。
4.2. 日志打印
现象: 磁盘 I/O 繁忙时服务吞吐量下降。
原因: printf
或同步日志库阻塞了 Event Loop。 解决:
使用异步日志库 (spdlog async mode)。
5. 总结
Libevent 编程的核心原则:非阻塞、线程安全、资源管理。时刻牢记这三点,就能避开 90% 的坑。
上一篇: 07-hardening/performance.md - 性能调优 下一篇: 08-projects/transparent-proxy.md - 实战:透明代理