【はじめに】製品開発において、現在のシステムが消費するメモリの総量をカウントすることで、製品に必要なメモリの総量を正確に評価し、適切なメモリチップとサイズを選択し、製品のコストを削減できます。 。メモリ リークなどの問題が発生した場合、この記事では、現在のシステムが消費する合計メモリの統計を通じて、製品の選択に必要な合計メモリを正確に見積もることができます。適切なメモリ チップとサイズを選択し、製品のコストを削減します。メモリ リークの問題が発生すると、多くの場合、私たちは無力になります。この記事では、proc 内のプロセス関連ファイルを分析して、システムが消費するメモリのサイズを正確に評価し、メモリ リークの問題を解決する方法を提供します。
Linux のメモリ使用の原則は、メモリが十分な場合は無駄に使用せず、メモリを使用して一部のファイルをキャッシュすることで、プロセスの実行速度を高速化することです。キャッシュ メモリは、プロセスで使用するために、対応するメモリ リサイクル戦略を通じて再利用されます。
1. 合計システム メモリの分析使用可能な物理メモリ = memfree+buffers+cached から、現在のシステム メモリ使用量の概要を確認できます。カーネルは、キャッシュおよびバッファリングされたメモリが、ライトバック メカニズム (pdflush スレッド) を通じてバッキング メモリに書き戻されることで、プロセスで使用するために関連するメモリを解放するか、キャッシュ メモリを手動で明示的に解放します。 HiSilicon プラットフォームでのメモリ全体の使用量では、システムが 29M のメモリを消費していることがわかります。これらのメモリを誰が消費しているかを分析してみましょう。
echo 3 > /proc/sys/vm/drop_caches
キャッシュ: 17260 kB SwapCached: 0 e: 21304 kB 非アクティブ: 19248 kB SwapTotal: 0 kB SwapFree: 0 kB Dirty: 0 kB Writeback: 0 kB AnonPages: 19216 kB マップ済み: 2472 kB スラブ: 6900 kB S回収可能: 924 kB S未回収: 5976 kB PageTables: 460 kB NFS_Unstable: 0 kB Bounce: 0 kB CommitLimit: 62060 kB Committed_AS: 2886 4 kB VmallocTotal: 442368 kB Vmalloc使用: 46984 kB Vmallocチャンク: 393212 kB
二、进程使用内存的统计 在32位操作系统中,每个进程拥有4G的虚拟内存空间,其中0~3GB是每个进程的私有用户空间,这个空间对系统中其他进程是不可见的。3~4GB是linux内核空间,由系统所有的进程以及内核所共享的。通过访问/proc/{pid}/下相关文件,可以了解每个线程虚拟内存空间的使用情况,从而了解每个线程所消耗内存的多少。 由于我们的产品都是使用多线程方式实现的,多个线程共享一个进程的用户态虚拟地址空间,虚拟地址空间包含若干区域,主要有如下几个区域: 1、当前执行文件的代码段,该代码段称为text段。 2、执行文件的数据段,主要存储执行文件用到的全局变量,静态变量。 3、存储全局变量和动态产生的数据的堆。 4、用于保存局部变量和实现函数调用的栈。 5、采用mmap方式映射到虚拟地址空间中的内存段 所以只需要查看任意一个线程的用户态虚拟地址空间分配即可知道属于同一进程的所有线程占用总内存的大小。可以通过查看/proc/{pid}/maps文件来获取相关的虚拟地址空间内容,下文摘列部分典型的内容: # cat /proc/568/maps ログイン後にコピー
第一行:从r-xp可知其权限为只读、可执行,该段内存地址对应于执行文件的代码段,程序的代码段需加载到内存中才可以执行。由于其只读,不会被修改,所以在整个系统内共享。 第二行:从rw-p可知其权限为可读写,不可执行,该段内存地址对应于执行文件的数据段,存放执行文件所用到的全局变量、静态变量。 第三行:从rwxp可知其权限是可读写,可执行,地址空间向上增长,而且不对应文件,是堆段,进程使用malloc申请的内存放在堆段。每个进程只有一个堆段,不论是主进程,还是不同的线程申请的内存,都反映到到进程的堆段。堆段向上增长,最大可以增长到1GB的位置,即0x40000000,如果大于1GB,glibc将采用mmap的方式,为堆申请一块内存。 第四行:是程序连接的共享库的内存地址。 第五行:是以mmap方式映射的虚拟地址空间。 第六、七行:是线程的栈区地址段,每个线程的栈大小都是16K。 第八行:是进程的栈区。关于栈段,每个线程都有一个,如果进程中有多个线程,则包含多个栈段。 三、当前系统总内存的统计 1、进程占用的总内存可以通过上述maps表计算出来。 2、当系统运行起来以后,会把应用层相关的文件挂载到tmpfs文件系统下,海思系统下这部分大概有13M左右,这部分内存是以cache方式统计出来的,但是这部分内存cache无法通过回收策略或者显式的调用释放掉。 3、根文件系统ramdisk占用的内存。 4、当前系统保留内存的大小,可以通过查看/proc/sys/vm/min_free_kbytes来获取或者修改此内存的大小。 5、当然,当系统运行起来后,还应该留有一定的内存用于在硬盘读写时做cache或者网络负荷比较高时分配skb等,一般需要30M以上。 四、对调试内存泄露类问题的一些启示 当进程申请内存时,实际上是glibc中内置的内存管理器接收了该请求,随着进程申请内存的增加,内存管理器会通过系统调用陷入内核,从而为进程分配更多的内存。 针对堆段的管理,内核提供了两个系统调用brk和mmap,brk用于更改堆顶地址,而mmap则为进程分配一块虚拟地址空间。 当进程向glibc申请内存时,如果申请内存的数量大于一个阀值的时候,glibc会采用mmap为进程分配一块虚拟地址空间,而不是采用brk来扩展堆顶的指针。缺省情况下,此阀值是128K,可以通过函数来修改此值。 #include <malloc.h> ログイン後にコピー Int mallopt(int param, int value) Param的取值分别为M_MMAP_THRESHOLD、M_MMAP_MAX。 Value的取值是以字节为单位的。 M_MMAP_THRESHOLD是glibc中申请大块内存阀值,大于该阀值的内存申请,内存管理器将使用mmap系统调用申请内存,如果小于该阀值的内存申请,内存管理器使用brk系统调用扩展堆顶指针。 M_MMAP_MAX是该进程中最多使用mmap分配地址段的数量。 如果在实际的调试过程中,怀疑某处发生了内存泄露,可以查看该进程的maps表,看进程的堆段或者mmap段的虚拟地址空间是否持续增加,如果是,说明很可能发生了内存泄露,如果mmap段虚拟地址空间持续增加,还可以看到各个段的虚拟地址空间的大小,从而可以确定是申请了多大的内存,对调试内存泄露类问题可以起到很好的定位作用。 |
以上がLinux でメモリ統計とメモリ リークを確認する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。