-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bthread: bthread_setspecific may cause memory leak #1449
Comments
There may have another scenario that can make memory leaked. First, we call bthread_getspecific(key1) which borrows a KeyTable from KeyTablePool, and it has old values in slot So, at now, we must call |
so, this memory leak is by design as the code comments. |
@cdjingit There are some differences, the code comments just explain that memory leaks may occur if borrowing KeyTable in |
@lorinlee As doc description, seems we MUST call bthread_getspecific to check KeyTables before bthread_setspecific. |
I had encountered this problem before, finally I created a wrapper class that ensure calling bthread_getspecific before bthread_setspecific: template<typename T>
class BThreadLocal {
public:
BThreadLocal() {
bthread_key_create(&m_key,
[](void* p) { delete (T*)p; });
}
T* get() const {
return (T*)bthread_getspecific(m_key);
}
T* get_or_create() {
T *p = get();
if (p == nullptr) {
p = new T();
set(p);
}
return p;
}
T *operator->() {
return get_or_create();
}
T &operator*() {
return *get_or_create();
}
private:
// User can't call set(), that may cause memory leak
int set(T* p) {
return bthread_setspecific(m_key, p);
}
bthread_key_t m_key;
}; |
Describe the bug (描述bug)
In the implementation of
bthread_setspecific
, if the current bthread has no KeyTable, a new KeyTable will be created. When the bthread ends, the created KeyTable will not be destroyed but returned to a KeyTablePool, which causes a memory leak. If we callbthread_getspecific
beforebthread_setspecific
, the memory leak will not happen becausebthread_getspecific
may borrow a KeyTable from KeyTablePool and makebthread_setspecific
reuse it.This memory leak can be reproduced except these situations:
brpc::thread_local_data()
beforebthread_setspecific
.brpc::thread_local_data()
callsbthread_getspecific
which may borrow a KeyTable from KeyTablePool, after that, allbthread_setspecific
will use this KeyTabe instead of creating new one.bthread_setspecific
, the reason is the same as above, the implementation of LOG() in brpc creates a LogStream which usesbthread_local
, and it callsbthread_getspecific
at first.bthread_getspecific
beforebthread_setspecific
, also the same as above.To Reproduce (复现方法)
we can simply modify the
echo_c++
inexample
to reproduce this behavior, the key code just like this.and we can add log in
bthread_setspecific
to see if a KeyTable created or not, the result is yes.Expected behavior (期望行为)
users can just call
bthread_setspecific
, instead of callingbthread_getspecific
at first.Versions (各种版本)
OS: Ubuntu 18.04.5 LTS
Compiler: g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
brpc: master branch, commit id: 0650582
protobuf: 3.0.0-9.1ubuntu1
Additional context/screenshots (更多上下文/截图)
The
bthread_setspecific
will create a new KeyTable and not borrow one from KeyTablePoolThe KeyTable will return to KeyTablePool when bthread ends.
The
bthread_getspecific
may borrow a KeyTable from KeyTablePool.The text was updated successfully, but these errors were encountered: