zoukankan      html  css  js  c++  java
  • Linux性能优化实战-内存篇

    linux性能优化之内存

    一、Linux内存是怎么工作的?
    • 什么是内存映射?

      • 虚拟内存地址到物理内存地址的映射机制

        • 页表 -> 存储在cpu的内存管理单元MMU/TLB,通过MMU通过TLB缓存页表,页表页大小4kb一页

        • 如果页表使用线性结构,整个虚拟地址空间需要占用大量的页表项 * 如何避免页表项过多 * 多级页表 -> 本质上是个多叉树 * 仅保留使用中的页,因此可以节省多数未使用的页表项 * 一级 -> 二级 -> 三级 -> 偏移量 => 物理地址 * 转换成线性结构: 1级 * 2级 * 3级 * 大页 -> 2MB、1GB

      • 什么是虚拟内存?

        • 进程独享的内存地址空间

          • 内核空间 -> 内核态可访问

          • 用户空间 -> 用户态可访问

        • 地址空间 -> 32位/64位范围

          • 虚拟内存 >> 物理内存

          • 分段

            • 只读 -> 常量,代码

            • 数据 -> 全局变量

            • 堆 -> 动态分配内存

            • 文件映射 -> 动态库,共享内存(进程共享)

            • 栈 -> 局部变量,函数调用上下文

    • 如何分配和回收内存?

      • 动态分配和释放

        • 堆 -> 适合小对象

          • brk()/free() 系统调用

          • 可重复使用,释放后不会立即归还系统

          • 容易导致内存碎片

        • 文件映射 -> 适合大对象

          • mmap()/unmap() 系统调用

          • 每次调用都会触发缺页异常

          • 释放后立刻归还系统

        • 物理内存分配管理机制

          • 页 -> 按页分配

          • SLAB -> 适合小对象

          • 其他

      • 系统回收

        • 回收缓存(LRU)

        • swap -> 交换不常用的内存到磁盘

          • 可能导致性能严重下降,例如ES等对性能要求严格的服务会禁用swap

        • OOM -> oom_score 打分机制

          • 内存高,cpu占用低的进程oom_score较大

          • 手动打分 -> echo -16 > /proc/$(pidof sshd)/oom_adj

          • 查看OOM日志 -> dmesg |grep -E 'kill|oom|out of memory'

    • 内存指标

      • free

        • total -> 总内存

        • used -> 已使用内存,包括share

        • free -> 未使用内存(排除了buff/cache/share

        • share -> 共享内存(共享 + 程序代码段 + 动态链接库)

        • buff/cache -> buffers(磁盘缓存) + cached(页缓存)+ SReclaim(可回收Slab)

          • slab -> 管理内核中的小块内存

        • available -> 可用内存

      • top

        • VIRT -> 虚拟内存(申请过的,即使没有实际分配物理内存)

          • 内核线程该指标=0

        • RES -> 常驻内存 (实际使用的物理内存,不包括swap)

        • SHR -> 共享内存(共享 + 程序代码段 + 动态链接库)

        • %MEM -> 物理内存占用 / 总内存

    二、怎样理解内存中的Buffer和Cache?

    Buffers是对原始磁盘块的临时存储,也就是用来缓存磁盘的数据(通常不会特别大)。Cached是从磁盘读取文件的页缓存,用来缓存从文件中读取的数据。Slab包括可回收和不可回收两部分。

    三、内存泄漏,如何定位和处理?

    虚拟内存分布从低到高分别是只读段,数据段,堆,内存映射段,栈五部分。其中会导致内存泄漏的是:

    堆: 由应用程序自己来分配和管理,除非程序退出这些堆内存不会被系统自动释放。 内存映射段:包括动态链接库和共享内存,其中共享内存由程序自动分配和管理 内存泄漏的危害比较大,这些忘记释放的内存,不仅应用程序自己不能访问,系统也不能把它们再次分配给其他应用。 内存泄漏不断累积甚至会耗尽系统内存。

    实验 如何检测内存泄漏 预先安装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函数分配的内存没有释放。定位到源码后查看源码来修复增加内存释放函数即可。

     

    内存性能指标

    系统内存指标

    • 已用内存/剩余内存

    • 共享内存 (tmpfs实现)

    • 可用内存: 包括剩余内存和可回收内存

    • 缓存:磁盘读取文件的页缓存,slab分配器中的可回收部分

    • 缓冲区: 原始磁盘块的临时存储,缓存将要写入磁盘的数据

    进程内存指标

    • 虚拟内存: 5大部分

    • 常驻内存: 进程实际使用的物理内存,不包括Swap和共享内存

    • 共享内存: 与其他进程共享的内存,以及动态链接库和程序的代码段

    • Swap内存: 通过Swap换出到磁盘的内存

    缺页异常

    • 可以直接从物理内存中分配,次缺页异常

    • 需要磁盘IO介入(如Swap),主缺页异常。 此时内存访问会慢很多

    内存性能工具

    根据不同的性能指标来找合适的工具: 

    内存分析工具包含的性能指标: 

    如何迅速分析内存的性能瓶颈

    通常先运行几个覆盖面比较大的性能工具,如free,top,vmstat,pidstat等

    • 先用free和top查看系统整体内存使用情况

    • 再用vmstat和pidstat,查看一段时间的趋势,从而判断内存问题的类型

    • 最后进行详细分析,比如内存分配分析,缓存/缓冲区分析,具体进程的内存使用分析等

    常见的优化思路:

    • 最好禁止Swap,若必须开启则尽量降低swappiness的值

    • 减少内存的动态分配,如可以用内存池,HugePage等

    • 尽量使用缓存和缓冲区来访问数据。如用堆栈明确声明内存空间来存储需要缓存的数据,或者用Redis外部缓存组件来优化数据的访问

    • cgroups等方式来限制进程的内存使用情况,确保系统内存不被异常进程耗尽

    • /proc/pid/oom_adj调整核心应用的oom_score,保证即使内存紧张核心应用也不会被OOM杀死

  • 相关阅读:
    Java——HTTPServletRequest的使用
    JavaWeb——HttpServletResponse的使用,文件下载
    JavaWeb——Servlet简介
    JavaWeb——TomCat服务器
    HTTP与HTTPS
    Java——DBCP连接池
    Java——JDBC连接MySQL
    Java——线程锁,死锁,等待唤醒机制
    LeetCode118. 杨辉三角
    LeetCode66. 加一
  • 原文地址:https://www.cnblogs.com/fzzf/p/13127110.html
Copyright © 2011-2022 走看看