cannot allocate memory in static TLS block问题记录

一、背景

最近发了一个新版本,服务升级后,加载动态库时候抛出了一个很奇怪的报错
“cannot allocate memory in static TLS block”,导致服务启动失败,但是在线下测试是没任何问题的。在解决问题后,做个小结

二、TLS

2.1 定义

TLS:全程是Thread Local Storage,即线程局部存储:在多线程中,存储和维护一些线程相关的数据,即线程之间隔离,因此也就没有多线程之间资源竞争问题。目的:因为数据线程局部,不需要锁来保护,可以利用这特性达到优化性能的目的。

2.2 实现方式

  1. gcc、clang等编译器可以通过修饰符__thread来声明实现。该方式很简单,本身需要编译器支持就可以,直接用__thread加在static或全局变量前即可,线程局部读取和设置。比如:
void thread_func()
{
    // 定义一个线程局部变量
    static __thread int a = 0;
        
    // 初始化变量为当前线程id
    if (!a) a = tb_thread_self();
}
  1. pthread库pthread_setspecific和pthread_getspecific接口
    ptherad库通过接口声明变量以及支持注册free函数,那么线程推出的时候,可以自动释放TLS内存
  2. windows下msvc的__declspec(thread)修饰符,和第一种方式类似

三、问题排查

3.1 一些思路

  1. 开始怀疑是机器堆栈内存不足,ulimti -a
    stack size (kbytes, -s) 8192
    因为之前机器装机模版是10240,改了之后还是不行
  2. 后来突然想到一个点,线上其实和线下使用方式不同,线上是通过dlopen使用的,感觉和这个是否有关

3.2 dlopen

#include 
// 功能: 以指定模式打开指定的动态链接库文件,并返回一个句柄给dlsym()的调用进程。
void *dlopen(const char *filename, int flag);
// 使用dlclose()来卸载打开的库。
int dlclose(void *handle);

3.3 原因

怀疑新版本TLS增大,导致dlopen失败了。开始去代码库中看最近的git提交,发现一个同学提交很有疑惑点:静态编译了jemalloc,版本为5.2以上。查询jemalloc的相关文档:找到如下

For performance reasons jemalloc 5 uses more TLS space. This causes isses for dlopen jemalloc where the pre allocated TLS may not be enough for jemalloc. The option --disable-initial-exec-tls in INSTALL.md should solve it for you

因此找相关同学修改编译方式,验证OK

其他一些思路:

  1. dlopen修改支持更大的TLS,参考:
    https://stackoverflow.com/questions/45640573/gulp-node-error-while-loading-shared-libraries-cannot-allocate-memory-in-stati
  2. ftls-model,参考:
    https://scc.ustc.edu.cn/zlsc/sugon/intel/compiler_c/main_cls/copts/ccpp_options/option_ftls_model.htm

你可能感兴趣的:(开发效能)