Linux性能优化
发布时间:2023-02-20 10:14:08 所属栏目:Linux 来源:互联网
导读:高并发和响应快对应着性能优化的两个核心指标:吞吐和延时。 应用负载角度:直接影响了产品终端的用户体验 系统资源角度:资源使用率、饱和度等 性能问题的本质就是系统资源已经到达瓶颈,但请求的处理还不够快,无法支撑更多的请求。性能分析实际上就是找出
栈 包括局部变量和函数调用的上下文等,栈的大小是固定的。一般8MB 内存分配与回收 分配 malloc对应到系统调用上有两种实现方式: brk() 针对小块内存(<128K),通过移动堆顶位置来分配。内存释放后不立即归还内存,而是被缓存起来。 **mmap()**针对大块内存(>128K),直接用内存映射来分配,即在文件映射段找一块空闲内存分配。 前者的缓存可以减少缺页异常的发生,提高内存访问效率。但是由于内存没有归还系统,在内存工作繁忙时,频繁的内存分配/释放会造成内存碎片。 后者在释放时直接归还系统,所以每次mmap都会发生缺页异常。在内存工作繁忙时,频繁内存分配会导致大量缺页异常,使内核管理负担增加。 上述两种调用并没有真正分配内存,这些内存只有在首次访问时,才通过缺页异常进入内核中,由内核来分配 回收 内存紧张时,系统通过以下方式来回收内存: 回收缓存:LRU算法回收最近最少使用的内存页面; 回收不常访问内存:把不常用的内存通过交换分区写入磁盘 杀死进程:OOM内核保护机制 (进程消耗内存越大oom_score越大,占用cpu越多oom_score越小,可以通过/proc手动调整oom_adj) echo -16 > /proc/$(pidof XXX)/oom_adj 如何查看内存使用情况? free来查看整个系统的内存使用情况 top/ps来查看某个进程的内存使用情况 VIRT 进程的虚拟内存大小 RES 常驻内存的大小,即进程实际使用的物理内存大小,不包括swap和共享内存 SHR 共享内存大小,与其他进程共享的内存,加载的动态链接库以及程序代码段 %MEM 进程使用物理内存占系统总内存的百分比 怎样理解内存中的Buffer和Cache? buffer是对磁盘数据的缓存,cache是对文件数据的缓存,它们既会用在读请求也会用在写请求中。 如何利用系统缓存优化程序的运行效率 缓存命中率 缓存命中率是指直接通过缓存获取数据的请求次数,占所有请求次数的百分比。命中率越高说明缓存带来的收益越高,应用程序的性能也就越好。 安装bcc包后可以通过cachestat和cachetop来监测缓存的读写命中情况。 安装pcstat后可以查看文件在内存中的缓存大小以及缓存比例。 #首先安装Go export GOPATH=~/go export PATH=~/go/bin:$PATH go get golang.org/x/sys/unix go ge github.com/tobert/pcstat/pcstat dd缓存加速: dd if=/dev/sda1 of=file bs=1M count=512 #生产一个512MB的临时文件 echo 3 > /proc/sys/vm/drop_caches #清理缓存 pcstat file #确定刚才生成文件不在系统缓存中,此时cached和percent都是0 cachetop 5 dd if=file of=/dev/null bs=1M #测试文件读取速度 #此时文件读取性能为30+MB/s,查看cachetop结果发现并不是所有的读都落在磁盘上,读缓存命中率只有50%。 dd if=file of=/dev/null bs=1M #重复上述读文件测试 #此时文件读取性能为4+GB/s,读缓存命中率为100% pcstat file #查看文件file的缓存情况,100%全部缓存 O_DIRECT选项绕过系统缓存: cachetop 5 sudo docker run --privileged --name=app -itd feisky/app:io-direct sudo docker logs app #确认案例启动成功 #实验结果表明每读32MB数据都要花0.9s,且cachetop输出中显示1024次缓存全部命中 但是凭感觉可知如果缓存命中读速度不应如此慢,读次数时1024,页大小为4K,五秒的时间内读取了1024*4KB数据,即每秒0.8MB,和结果中32MB相差较大。说明该案例没有充分利用缓存,怀疑系统调用设置了直接I/O标志绕过系统缓存。因此接下来观察系统调用。 strace -p $(pgrep app) #strace 结果可以看到openat打开磁盘分区/dev/sdb1,传入参数为O_RDONLY|O_DIRECT 这就解释了为什么读32MB数据那么慢,直接从磁盘读写肯定远远慢于缓存。找出问题后我们再看案例的源代码发现flags中指定了直接IO标志。删除该选项后重跑,验证性能变化。 内存泄漏,如何定位和处理? 对应用程序来说,动态内存的分配和回收是核心又复杂的一个逻辑功能模块。管理内存的过程中会发生各种各样的“事故”: 没正确回收分配的内存,导致了泄漏 访问的是已分配内存边界外的地址,导致程序异常退出 内存的分配与回收 虚拟内存分布从低到高分别是只读段,数据段,堆,内存映射段,栈五部分。其中会导致内存泄漏的是: 堆:由应用程序自己来分配和管理,除非程序退出这些堆内存不会被系统自动释放。 内存映射段:包括动态链接库和共享内存,其中共享内存由程序自动分配和管理 内存泄漏的危害比较大,这些忘记释放的内存,不仅应用程序自己不能访问,系统也不能把它们再次分配给其他应用。 内存泄漏不断累积甚至会耗尽系统内存. 如何检测内存泄漏 预先安装systat,docker,bcc: sudo docker run --name=app -itd feisky/app:mem-leak sudo docker logs app vmstat 3 可以看到free在不断下降,buffer和cache基本保持不变。说明系统的内存一致在升高。但并不能说明存在内存泄漏。此时可以通过memleak工具来跟踪系统或进程的内存分配/释放请求: /usr/share/bcc/tools/memleak -a -p $(pidof app) 从memleak输出可以看到,应用在不停地分配内存,并且这些分配的地址并没有被回收。通过调用栈看到是fibonacci函数分配的内存没有释放。定位到源码后查看源码来修复增加内存释放函数即可。 为什么系统的Swap变高 系统内存资源紧张时通过内存回收和OOM杀死进程来解决。其中可回收内存包括: 缓存/缓冲区,属于可回收资源,在文件管理中通常叫做文件页 在应用程序中通过fsync将脏页同步到磁盘 交给系统,内核线程pdflush负责这些脏页的刷新 被应用程序修改过暂时没写入磁盘的数据(脏页),要先写入磁盘然后才能内存释放 内存映射获取的文件映射页,也可以被释放掉,下次访问时从文件重新读取 对于程序自动分配的堆内存,也就是我们在内存管理中的匿名页,虽然这些内存不能直接释放,但是Linux提供了Swap机制将不常访问的内存写入到磁盘来释放内存,再次访问时从磁盘读取到内存即可。 Swap原理 Swap本质就是把一块磁盘空间或者一个本地文件当作内存来使用,包括换入和换出两个过程: 换出:将进程暂时不用的内存数据存储到磁盘中,并释放这些内存 换入:进程再次访问内存时,将它们从磁盘读到内存中 Linux如何衡量内存资源是否紧张? 直接内存回收 新的大块内存分配请求,但剩余内存不足。此时系统会回收一部分内存; kswapd0 内核线程定期回收内存。为了衡量内存使用情况,定义了pages_min,pages_low,pages_high三个阈值,并根据其来进行内存的回收操作。 剩余内存 < pages_min,进程可用内存耗尽了,只有内核才可以分配内存 pages_min < 剩余内存 < pages_low,内存压力较大,kswapd0执行内存回收,直到剩余内存 > pages_high pages_low < 剩余内存 < pages_high,内存有一定压力,但可以满足新内存请求 剩余内存 > pages_high,说明剩余内存较多,无内存压力 pages_low = pages_min 5 / 4 pages_high = pages_min 3 / 2 NUMA 与 SWAP 很多情况下系统剩余内存较多,但SWAP依旧升高,这是由于处理器的NUMA架构。 在NUMA架构下多个处理器划分到不同的Node,每个Node都拥有自己的本地内存空间。在分析内存的使用时应该针对每个Node单独分析: numactl --hardware #查看处理器在Node的分布情况,以及每个Node的内存使用情况 内存三个阈值可以通过/proc/zoneinfo来查看,该文件中还包括活跃和非活跃的匿名页/文件页数。 当某个Node内存不足时,系统可以从其他Node寻找空闲资源,也可以从本地内存中回收内存。通过/proc/sys/vm/zone_raclaim_mode来调整。 0表示既可以从其他Node寻找空闲资源,也可以从本地回收内存 (编辑:莱芜站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
相关内容
- linux – 家庭作业:如何使用bash shell记录审核流程?
- linux – 什么是活动内存和非活动内存[已关闭]
- linux – iwconfig – 通过wifi在终端上连接网络
- linux – XMonad:dmenu在启动时没有启动/生成
- linux – [01000] [unixodBC] [Driver Manager]无法打开lib
- linux – 有没有办法让BIND 9自动将其缓存转储到文件中,然后
- linux – cgroups隔离(分离组进程)
- linux – Gnome Shell扩展密钥绑定
- linux – 当RAM几乎一半免费时使用交换
- 为什么/usr/include/linux/stddef.h为空?