Glibc内存管理--ptmalloc2源代码分析(十)

3.2.7 使用注意事项

为了避免Glibc内存暴增,使用时需要注意以下几点:

后分配的内存先释放,因为ptmalloc收缩内存是从top chunk开始,如果与top chunk相邻的chunk不能释放,top chunk以下的chunk都无法释放。

  1.   Ptmalloc不适合用于管理长生命周期的内存,特别是持续不定期分配和释放长生命周期的内存,这将导致ptmalloc内存暴增。如果要用ptmalloc分配长周期内存,在32位系统上,分配的内存块最好大于1MB64位系统上,分配的内存块大小大于32MB。这是由于ptmalloc默认开启mmap分配阈值动态调整功能,1MB32位系统mmap分配阈值的最大值,32MB64位系统mmap分配阈值的最大值,这样可以保证ptmalloc分配的内存一定是从mmap映射区域分配的,当free时,ptmalloc会直接把该内存返回给操作系统,避免了被ptmalloc缓存。
  2. 不要关闭ptmallocmmap分配阈值动态调整机制,因为这种机制保证了短生命周期的内存分配尽量从ptmalloc缓存的内存chunk中分配,更高效,浪费更少的内存。如果关闭了该机制,对大于128KB的内存分配就会使用系统调用mmap向操作系统分配内存,使用系统调用分配内存一般会比从ptmalloc缓存的chunk中分配内存慢,特别是在多线程同时分配大内存块时,操作系统会串行调用mmap(),并为发生缺页异常的页加载新物理页时,默认强制清0。频繁使用mmap向操作系统分配内存是相当低效的。使用mmap分配的内存只适合长生命周期的大内存块。
  3. 多线程分阶段执行的程序不适合用ptmalloc,这种程序的内存更适合用内存池管理,就像Appach那样,每个连接请求处理分为多个阶段,每个阶段都有自己的内存池,每个阶段完成后,将相关的内存就返回给相关的内存池。Google的许多应用也是分阶段执行的,他们在使用ptmalloc也遇到了内存暴增的相关问题,于是他们实现了TCMalloc来代替ptmallocTCMalloc具有内存池的优点,又有垃圾回收的机制,并最大限度优化了锁的争用,并且空间利用率也高于ptmallocPtmalloc假设了线程A释放的内存块能在线程B中得到重用,但B不一定会分配和A线程同样大小的内存块,于是就需要不断地做切割和合并,可能导致内存碎片。
  4. 尽量减少程序的线程数量和避免频繁分配/释放内存,Ptmalloc在多线程竞争激烈的情况下,首先查看线程私有变量是否存在分配区,如果存在则尝试加锁,如果加锁不成功会尝试其它分配区,如果所有的分配区的锁都被占用着,就会增加一个非主分配区供当前线程使用。由于在多个线程的私有变量中可能会保存同一个分配区,所以当线程较多时,加锁的代价就会上升,ptmalloc分配和回收内存都要对分配区加锁,从而导致了多线程竞争环境下ptmalloc的效率降低。
  5.   防止内存泄露,ptmalloc对内存泄露是相当敏感的,根据它的内存收缩机制,如果与top chunk相邻的那个chunk没有回收,将导致top chunk一下很多的空闲内存都无法返回给操作系统。
  6. 防止程序分配过多内存,或是由于Glibc内存暴增,导致系统内存耗尽,程序因OOM被系统杀掉。预估程序可以使用的最大物理内存大小,配置系统的/proc/sys/vm/overcommit_memory/proc/sys/vm/overcommit_ratio,以及使用ulimt –v限制程序能使用虚拟内存空间大小,防止程序因OOM被杀掉。

你可能感兴趣的:(Glibc内存管理--ptmalloc2源代码分析(十))