zoukankan      html  css  js  c++  java
  • 内存理论及磁盘文件写案例

    一. 上节回顾

    1. PHP的问题定位

    2. CPU的三个主要案例:

    (1) mysql 

    (2) java

    (3) PHP

    二. 内存

    1. 物理内存

    生活中,我们知道内存有4G和8G,这里提到的是内存容量,其实指的是物理内存

    物理内存:也称为主存,大多数计算机的主存都是动态随机访问内存(DRAM)

    2. 虚拟内存

    只有内核才能直接访问物理内存,那么,应用进程要访问内存时,怎么办?

    Linux内核给每个进程都提供了一个独立的虚拟地址空间,并且这个空间是连续的,这样进程就可以很方便的访问内存,更确切的说是访问虚拟内存

    虚拟地址空间的内部又被分为内核空间和用户空间两部分,不同字长(也就是单个CPU指令可以处理数据的最大长度)的处理器,地址空间的范围也不同,比如64位系统,32位系统

    我们都知道,进程在用户态时,只能访问用户空间内存,只有进入内核态后,才可以访问内核空间内存,虽然每个进程的地址空间都包含了内核空间,但这些内核空间,其实关联的都是相同的物理内存,这样,进程切换到内核态后,就可以很方便的访问内核空间内存

    3. 内存映射

    每个进程都有一个这么大的地址空间,那么所有进程的虚拟内存加起来,自然要比实际的物理内存大的多,所以并不是所有的虚拟内存都会分配物理内存,只有那些实际使用的虚拟内存才会分配物理内存,并且分配后的物理内存,是通过内存映射来管理的

    内存映射:就是将虚拟内存地址映射到物理内存地址,为了完成内存映射,内核为每个进程都维护了一张页表,记录虚拟地址和物理地址的映射关系

    页表实际上存储在CPU的内存管理单元MMU中,这样,正常情况下,处理器就可以直接通过硬件,找出要访问的内存

    4. 内存使用

    通过上面的页表映射,进程就可以通过虚拟地址来访问物理内存了,那么具体一个Linux进程中这些内存又是怎么使用的呢?

    以32位系统为例,从低到高有五种不同的内存段:

    只读段:包括代码和常量等

    数据段:包括全局变量等

    堆:包括动态分配的内存,从低地址开始向上增长

    文件映射:包括动态库,共享内存,从高地址开始向下增长

    栈:包括局部变量和函数调用的上下文,栈的大小都是固定的,一般是8MB

    在这五个内存段中,堆和文件映射的内存是动态分配的

    5. 内存分配与回收

    malloc()是C标准库提供的内存分配函数,对应到调用系统上,有两种实现方式:brk()和mmap()

    对于存储小于128K,C标准库使用brk()来分配,也就是通过移动堆顶的位置来分配内存,这些内存释放之后并不会立即归还系统,而是被缓存起来,这样就可以重复使用

    对于大块内存大于128K的,直接使用内存映射mmap()来分配,就是在文件映射段中找一块内存分配出去

    优缺点:

    brk()方式的缓存:可以减少缺页异常的发生,提高内存访问效率,不过由于这些内存没有归还系统,在内存工作繁忙时,频繁的内存分配和释放会造成内存碎片

    mmap()方式分配的内存:会在释放时直接归还系统,所以每次mmap都会发生缺页异常,在内存工作繁忙时,频繁的内存分配会导致大量的缺页异常,使内核的管理负担增大,这也是malloc只对大块内存使用mmap的原因

    对内存来说,如果只分配而不释放,就会造成内存泄漏,甚至会耗尽系统内存,所以在应用程序用完内存后,还需要调用free()或unmap(),来释放内存

    当然,系统也不会任由某种进程用完所有内存,在发现内存紧张时,系统会通过一系列的机制来回收内存,如下三种:

    第一种:回收缓存,使用LRU(Least Recently used)算法,回收最近使用最少的内存页面

    第二种:回收不常用的内存,把不常用的内存通过交换分区直接写到磁盘中

    第三种:杀死进程,内存紧张时系统会跳过OOM(OutOfMemory),直接杀掉占用大量内存的进程

    其中第二种回收不常用的内存时,就会用到交换分区(swap),swap其实就是把一块磁盘空间当做内存来使用,它可以把进程暂时不用的数据存储到磁盘中(这个过程称为换出),当进程访问这些内存时,再从磁盘读取这些数据到内存中(这个过程称为换入)

    所以,发现swap把系统的可用内存变大了。但要注意,通常只有在内存不足时,才会发送swap交换,并且由于磁盘读写的速度远比内存慢,swap会导致严重的内存性能问题

    第三种方式OOM,是内核的一种保护机制,它监控进程的内存使用情况,并且使用oom_score为每个进程的内存使用进行评分:

    一个进程消耗的内存越大,oom_score越大

    一个进程消耗的内存越小,oom_score越小

    这样,进程的oom_score越大,代表消耗的内存越大, 也就很容易被OOM掉,从而可以更好的保护系统

    三. 查看内存使用情况的工具

    1. 第一个查看内存的性能工具:free

    free
    free -h
    free -m

    total:总的内存大小

    used:已使用内存的大小

    free:未使用内存的大小

    shared:共享内存的大小

    buff/cache:缓存和缓冲区的大小

    available:新进程可用内存的大小

    注意:available不仅包含未使用的内存,还包括了可回收的缓存

    2. top

    上面可以看出free显示的是整个系统的内存使用情况,想要查看进程的内存使用情况,可以使用top或者ps等工具

    这些输出,包含了进程最重要的几个内存使用情况

    VIRT:进程虚拟内存的大小,只要是进程申请过的内存,即便还没有真正分配物理内存,也会计算在内

    RES:常驻内存的大小,也就是进程实际使用的物理内存大小,但不包括swap和共享内存

    SHR:共享内存的大小,比如与其他进程共同使用的共享内存,加载的动态链接库以及程序的代码段

    %MEM:进程使用物理内存占系统总内存的百分比

    需要注意:

    (1) 虚拟内存通常并不会全部分配物理内存,从上面的输出,可以发现每个进程的虚拟内存都比常驻内存大得多

    (2) 共享内存SHR也不一定是共享的,比如说,程序的代码段,非共享的动态链接库,也都算在SHR里面。当然,SHR也包括了进程间真正共享的内存,在计算多个进程的内存使用时,不要把所有进程的SHR直接相加得出结果

    buff和cache:从字面上来说,buff是缓冲区,而cache是缓存,两者都是数据在内存中的临时存储,这两种有什么区别?

    buff:是对原始磁盘块的临时存储,也就是用来缓存磁盘的数据,通常不会特别大(20MB左右)

    cache:是从磁盘读取文件的页缓存,也就是用来缓存从文件读取的数据

    两个问题:

    (1) buff是磁盘读数据还是写数据的缓存?

    (2) cache是对文件读数据的缓存,那么是不是也会缓存写文件的数据?

    四. 场景案例

    1. 场景一:磁盘和文件写案例

    准备工作:先安装sysstat

    (1) 先清理缓存,清理文件页,目录项,inodes等各种缓存

    echo 3 > /proc/sys/vm/drop_caches   #通过proc文件系统修改内核行为,写入3表示清理文件,目录项,inodes等各种缓存

    (2) 在第一个终端输入:vmstat 1

    在输出界面中,内存部分的buff和cache,io的bi、bo是需要重点关注的,bi和bo分别表示块设备读取和写入的大小

    (3) 在第二个终端执行dd命令,读取随机设备,生成一个200MB大小的文件。在第一个终端,观察buff和cache的变化情况

    dd if=/dev/urandom of=/data/file bs=200M count=500

    观察vmstat的输出,发现在dd命令运行时,cache在不停的增长,而buff没有变化

    进一步观察I/O的情况,会看到在cache刚开始增长时,bi只出现了16KB/s,bo刚开始也很小,但是一下子会出现大量的快设备写入,bo达到40000以上

    当dd命令结束后,cache不会增长,但块设备写入还会持续一段时间,并且多次I/O写的结果加起来,才是dd要写的500 x 200M的数据

    通过案例,发现写文件时也会用到cache缓存数据,而写磁盘会用到buff来缓存数据

  • 相关阅读:
    百度云管家开机启动如何取消
    双语小说阅读:《谁动了我的奶酪》
    [Swift]方法
    Swift中的类型属性(静态变量)
    Swift 学习之二十一:?和 !(详解)
    苹果Swift可为Windows/Android开发软件了
    iOS7下滑动返回与ScrollView共存二三事
    swift c++ oc 混编
    RTOS
    STM32 RTC
  • 原文地址:https://www.cnblogs.com/my_captain/p/12684636.html
Copyright © 2011-2022 走看看