Kubernetes Pod内gRPC服务内存分配失败问题咨询
Kubernetes中gRPC服务内存分配异常问题
我在Kubernetes中部署了一个gRPC服务,所有内存分配均通过tcmalloc完成,但Pod频繁出现内存不足问题。以下是堆栈追踪信息:
terminate called after throwing an instance of 'std::length_error' what(): basic_string::_M_create *** Aborted at 1668932192 (unix time) try "date -d @1668932192" if you are using GNU date *** PC: @ 0x0 (unknown) *** SIGABRT (@0x1) received by PID 1 (TID 0x7f2e45bd3700) from PID 1; stack trace: *** @ 0x7f2e4c7d63c0 (unknown) @ 0x7f2e4c4a918b gsignal @ 0x7f2e4c488859 abort @ 0x7f2e4c8a1951 (unknown) @ 0x7f2e4c8ad47c (unknown) @ 0x7f2e4c8ad4e7 std::terminate() @ 0x7f2e4c8ad799 __cxa_throw @ 0x7f2e4c8a4366 std::__throw_length_error() @ 0x7f2e4c9459fc std::__cxx11::basic_string<>::_M_create() @ 0x561821534960 __gnu_cxx::new_allocator<>::construct<>() @ 0x56182153390b metrics::ReadReporter::Report() @ 0x56182125cb54 std::_Function_handler<>::_M_invoke() @ 0x56182151f2aa std::_Function_handler<>::_M_invoke() @ 0x56182154092e std::_Function_handler<>::_M_invoke() @ 0x56182153f5e5 file::HttpRequest::Invoke() @ 0x7f2e4c8d9d84 (unknown) @ 0x7f2e4c7ca609 start_thread @ 0x7f2e4c585293 clone @ 0x0 (unknown) terminate called recursively terminate called recursively external/com_google_tcmalloc/tcmalloc/tcmalloc_policy.h:102] Unable to allocate (new failed) 8111000728417 @ 0x561822037742 0x56182200fc67 0x561822003b0f 0x561821534960 0x56182153390b 0x56182125cb54 0x56182125d10a 0x56182151f2aa 0x56182154092e 0x56182153f5e5 0x561821545432 0x7f2e4c8d9d84 See https://github.com/google/tcmalloc/tree/master/docs/stats.md for an explanation of this page
我已为该服务配置了就绪探针和存活探针,仅通过一个线程监听并响应TCP请求。我的疑问如下:
- 为何Pod未触发OOM(堆栈中已显示抛出SIGABRT)并被Kubernetes重启?
- 我知道可通过增加容器内存配额、添加限流来临时解决,但这是否是最优方案?
问题解答
1. 为何未触发OOM而是抛出SIGABRT?
Kubernetes的OOM Killer触发的前提是容器进程尝试申请内存时,节点的cgroup内存限制被耗尽,此时内核会发送SIGKILL终止进程。但你的情况是应用本身主动抛出异常并触发了SIGABRT:
- 从堆栈看,
std::length_error是在metrics::ReadReporter::Report()中创建std::string时抛出的,原因是尝试分配的内存大小异常(8111000728417字节,约7.37TB),这个数值明显超出合理范围,大概率是代码中存在逻辑错误(比如未初始化的变量作为字符串长度传入)。 - tcmalloc在尝试分配这个超大内存块失败后,C++标准库抛出了未捕获的异常,最终触发
std::terminate()调用abort()发送SIGABRT终止进程。此时容器的内存使用可能还没达到Kubernetes配置的内存配额上限,所以OOM Killer没有被触发。
2. 增加配额或限流是否是最优方案?
不是,这只是临时规避手段,最优方案是修复代码中的根本问题:
- 定位到
metrics::ReadReporter::Report()方法,检查其中创建std::string的逻辑:是否存在计算字符串长度时的溢出、未初始化变量、错误的数值转换(比如将指针值当作长度)等问题。 - 异常的分配大小
8111000728417是一个极大的数,几乎可以肯定是代码逻辑错误导致的非法长度值,而非正常的内存需求增长。 - 即使增加内存配额,这种非法的超大内存分配请求依然会失败,最终还是会触发SIGABRT;限流只能降低触发频率,但无法解决根源问题。
建议先排查并修复metrics::ReadReporter::Report()中的字符串创建逻辑,再结合tcmalloc的内存统计工具分析正常业务的内存使用情况,按需调整配额或添加限流策略。
内容的提问来源于stack exchange,提问作者Tinyden
相关产品推荐
相关产品推荐

