【银河麒麟操作系统】ptmalloc内存释放原理及优化方案

现象描述

现象描述:接收java压测工具发出的交易请求时(压测程序没运行在故障机器上,压测程序会向故障机发送交易请求,故障机返回请求结果,按理说不会占用大量内存资源),故障机内存使用量缓慢上升,整体内存使用率在70%以上;

故障概率:非个体问题,多台机器出现;短则压测3-4小时,多则压测一晚上即可复现;

虚机情况:故障机全部是虚机,每台虚机16个核,32G内存;

业务情况:主要部署2个应用,通过内存使用率来看,70%处理邮储行内交易请求/30%处理银联交易请求,业务进程大概40个线程;

目标:优化ptmalloc工具释放内存的机制,尽量保持整体内存使用率在70%以下

ptmalloc内存释放流程

ptmalloc内存释放流程

free() 函数接受一个指向分配区域的指针作为参数,释放该指针所指向的 chunk。而具体的释放方法则看该 chunk 所处的位置和该 chunk 的大小。

     

图3.1

free()函数的工作步骤如下:

(1) free()函数同样首先需要获取分配区的锁,来保证线程安全。

(2) 判断传入的指针是否为 0,如果为 0,则什么都不做,直接 return。否则转下一步。

(3) 判断所需释放的 chunk 是否为 mmaped chunk,如果是,则调用 munmap()释放mmaped chunk,解除内存空间映射,该空间不再有效。如果开启了 mmap 分配阈值的动态调整机制,并且当前回收的 chunk 大小大于 mmap 分配阈值,将 mmap 分配阈值设置为该 chunk 的大小,将 mmap 收缩阈值设定为 mmap 分配阈值的 2 倍,释放完成,否则跳到下一步。

(4) 判断 chunk 的大小和所处的位置,若 chunk_size <= max_fast,并且 chunk 并不位于 heap 的顶部,也就是说并不与 top chunk 相邻,则转到下一步,否则跳到第 6 步。 (因为与 top chunk 相邻的小 chunk 也和 top chunk 进行合并,所以这里不仅需要 判断大小,还需要判断相邻情况)

(5) 将 chunk 放到 fast bins 中,chunk 放入到 fast bins 中时,并不修改该 chunk 使用状 态位 P。也不与相邻的 chunk 进行合并。只是放进去,如此而已。这一步做完之后 释放便结束了,程序从 free()函数中返回。

(6) 判断前一个 chunk 是否处在使用中,如果前一个块也是空闲块,则合并。并转下一 步。

(7) 判断当前释放 chunk 的下一个块是否为 top chunk,如果是,则转第 9 步,否则转 下一步。

(8) 判断下一个 chunk 是否处在使用中,如果下一个 chunk 也是空闲的,则合并,并将合并后的 chunk 放到 unsorted bin 中。注意,这里在合并的过程中,要更新 chunk的大小,以反映合并后的 chunk 的大小。并转到第 10 步。

(9) 如果执行到这一步,说明释放了一个与 top chunk 相邻的 chunk。则无论它有多大,都将它与 top chunk 合并,并更新 top chunk 的大小等信息。转下一步。

(10) 判断合并后的 chunk 的大小是否大于 FASTBIN_CONSOLIDATION_THRESHOLD(默认 64KB),如果是的话,则会触发进行 fast bins 的合并操作,fast bins 中的 chunk 将被 遍历,并与相邻的空闲 chunk 进行合并,合并后的 chunk 会被放到 unsorted bin 中。fast bins 将变为空,操作完成之后转下一步。

(11) 判断 top chunk 的大小是否大于 mmap 收缩阈值(默认为 128KB),如果是的话,对于主分配区,则会试图归还 top chunk 中的一部分给操作系统。但是最先分配的 128KB 空间是不会归还的,ptmalloc 会一直管理这部分内存,用于响应用户的分配请求;如果为非主分配区,会进行 sub-heap 收缩,将 top chunk 的一部分返回给操作系统,如果 top chunk 为整个 sub-heap,会把整个 sub-heap 还回给操作系统。做完这一步之后,释放结束,从 free() 函数退出。可以看出,收缩堆的条件是当前 free 的 chunk 大小加上前后能合并 chunk 的大小大于 64k,并且要 top chunk 的大小要达到 mmap 收缩阈值,才有可能收缩堆。

ptmalloc与jemalloc对比

ptmalloc‌ 是 glibc 的一部分,它是标准 C 库中的内存分配器,用于处理基本的内存分配需求。它的设计目标是提供稳定和可靠的内存分配服务,而不是特别强调性能优化

‌jemalloc‌ 是 BSD 系统提供的内存分配器,主要特点是带有线程缓存,为每个线程分配了一个局部缓存。jemalloc 在设计上注重减少内存碎片化,提高内存使用的效率。jemalloc 定期检查内存使用情况,并根据gc策略判断是否需要将空闲内存返还给操作系统,使得它更容易在内存不再需要时释放回操作系统。它适用于需要高性能内存管理和优化内存碎片化的场景,例如服务器端应用和服务程序。‌‌

ptmalloc 作为标准库的一部分,适用于大多数基本的内存分配需求。而 jemalloc 则更适合需要优化内存碎片化和提高内存使用效率的场景,如高性能计算和服务器端应由于机制实现不同,所以内存分配与内存碎片处理也会不同,ptmalloc占用内存过大是由于内存分配器设计方式导致的

分析总结

根据ptmalloc内存释放流程,可能造成内存一直不释放的原因:

  1. 多线程锁开销大,多线程应用在内存分配时,发现其他分配区被锁,会申请新的非主分配区默认64M,当多次申请时,会有多个分配区,针对64位系统最多会申请8* cpu核个的分配区。
  2. ptmalloc只有top chunk满足默认128K才将内存归还至系统,如果应用释放的内存非连续,或者合并后无法达到128K,部分内存会无法释放,会放在相应的bins中。
  3. 内存从thread的areana中分配, 内存不能从一个arena移动到另一个arena, 就是说如果多线程使用内存不均衡,容易导致内存的浪费。比如说线程1使用了300M内存,完成任务后ptmalloc没有释放给操作系统,线程2开始创建了一个新的arena, 但是线程1的300M却不能用了。

上述三种情况会造成占用内存无法快速释放,该现象也是ptmalloc内存分配器设计方式导致的。

规避方案及优化建议

Glibc的内存分配器ptmalloc内存释放条件是堆顶存在大于等于128K的空闲区时才会释放。频繁多次申请,如果释放的内存无法与top chunk连续或者释放的内存分布在不同分配区,glibc会将这段内存缓存起来并不会真正释放,从现象看内存一直被占用无法得到释放。该现象是ptmalloc内存分配器设计方式导致的

ptmalloc参数

根据可能原因,提供以下系统参数供参考,具体需要根据应用场景来确定:

1、限制分配区的个数,调整glibc.malloc.arena_max参数, 减少非主分配区的内存占用,若影响应用性能有,系统可以使用ptmalloc的tcache机制,针对1K以下的内存,适当调大glibc.malloc.tcache_count参数,增加tcache容量。根据用户环境为16核,最多会有96个分配区,可以减小此参数来减小内存占用。

2、可以调整默认值128K的参数:glibc.malloc.trim_threshold,缩小释放大小限制,主要为了内存尽快释放,需要根据业务来设置验证。

3、调整glibc.malloc.mmap_threshold参数(默认128K),内存申请时,走系统的mmap系统调用,释放时也会直接归还系统。需要根据业务来设置验证。

系统参数设置方法

在启动application进程时的设置如下:

GLIBC_TUNABLES="glibc.malloc.tcache_max=0x100:glibc.malloc.trim_threshold=0x10000" ./application  

启动应用程序时,前面加上要设置的环境变量,多个变量就用冒号分割,此设置只会影响启动的application  进程 ,不会影响其他进程。

​​​​​​​用户编程建议

  1. 为了保证只对单一进程的影响,上述参数建议用户态使用mallopt的参数选项来直接调整malloc的默认行为,具体参数大小可以根据业务场景进行分析调整。

2、编程使用小内存频繁分配时,建议使用内存池,统一管理内存,减少内存碎片发生,保证多使用mmap系统调用与大块内存。

3、建议用户态显示调用malloc_trim()方法,将碎片的物理内存释放掉,真正访问的时候,再触发缺页中断。

4、使用第三方内存分配器jemalloc或者tcmalloc,来降低内存碎片化。

​​​​​​​优化总结

ptmalloc系统参数的设置,根据现提供业务信息分析,可以调整缩小glibc.malloc.arena_max参数,这个参数最大值是由cpu核*8,可以初步缩小验证。为了保证小于1K的内存申请效率,可以增大glibc.malloc.tcache_count的值(默认为7)。后两个参数需要根据业务分析才能确定,也可以尝试调整验证。

用户编程,开发过程中,可以适当使用内存池与malloc_trim()来减少内存碎片的产生。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值