引用:
- http://blog.csdn.net/jasonchen_gbd/article/details/51367650
- https://en.wikipedia.org/wiki/Thread-local_storage
- http://brionas.github.io/2015/01/31/jemalloc%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90-%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/
缩写:
- tsd == thread specific data
- tls == thread local storage
jemalloc 使用:tsd.h 文件。
先介绍下 jemalloc 的内存分配机制, Je对内存划分按照如下由高到低的顺序:
- 内存是由一定数量的 arenas 进行管理.
- 一个 arena 被分割成若干 chunks, 后者主要负责记录 bookkeeping.
- chunk 内部又包含着若干 runs, 作为分配小块内存的基本单元.
- run 由 pages 组成, 最终被划分成一定数量的regions.
- 对于 small size 的分配请求来说, 这些 region 就相当于user memory.

说明:
- arena 的个数在某些情况下不只一个
- 每个线程持有各自的 tcache 副本,tcache 每次从 arena 批发一批内存,malloc 在向 tcache 申请内存时不需要加锁。
- arena 向系统一次性申请一大块内存,按照不同大小切割成块 run,run 再将这些块切成更小的块 regions,region 是一定大小(如 16B, 32B等)的分配给用户的内存, regions 可供 tcache 批发,这些内存的分配是由 chunk 这个数据结构管理,chunk 会记录一些簿记信息。
chunk 内存结构



chunk 是按照一定大小(比如 2M)向系统申请的,所以直接根据地址本身就可以找到 chunk 头数据结构,通过 ptr 找到所属 chunk 方法:
#define CHUNK_ADDR2BASE(a) ((void *)((uintptr_t)(a) & ~chunksize_mask))
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
实现线程局部存储方法:
- 通过 __thread 修饰符修饰。
- 使用 pthread 库机制。
要点:
- 要定义一个线程局部变量很简单,只需简单的在全局或静态变量的声明中包含__thread说明符即可。
- __thread变量并不是在线程之间完全隐藏的,每个线程保存自己的一份拷贝,因此每个线程的这个变量的地址不同。但这个地址是整个进程可见的,因此一个线程获得另外一个线程的局部变量的地址,就可以修改另一个线程的这个局部变量。
- POSIX thread使用getthreadspecific和setthreadspecific 组件来实现这一特性,因此编译要加-pthread,但是使用这种方式使用起来很繁琐,并且效率很低。例子参照引用1。
网友评论