0%

内存缺页错误

#b计算机基础/c_计算机系统/b_linux系统/补充
2019年5月5日 下午2:20

程序员的自我修养(七):内存缺页错误 | 始终

2020年5月2日 下午11:14更新

总结:

  • 缺页的功能,不属于linux的独立核心功能。缺页功能的完成依托于进程的调度(缺页中断就会调度另外的进程去找那些你需要的数据)、文件系统(涉及到文件的查找,当然免不了文件系统)

  • 作者列出的两个引起内存缺页的场景,我觉得特别有用。

  • 1.内存页和缺页错误 .

    • 1.1.分页模式
      • 好处:
        • 允许虚存空间远大于实际物理内存大小的情况
        • 减少了内存碎片的产生
    • 1.2.缺页错误
      • 当进程在进行一些计算时,CPU 会请求内存中存储的数据。在这个请求过程中,CPU 发出的地址是逻辑地址(虚拟地址),然后交由 CPU 当中的 MMU 单元进行内存寻址,找到实际物理内存上的内容。若是目标虚存空间中的内存页(因为某种原因),在物理内存中没有对应的页帧,那么 CPU 就无法获取数据。这种情况下,CPU 是无法进行计算的,于是它就会报告一个缺页错误(Page Fault)。
      • 缺页的流程:
        • 因为 CPU 无法继续进行进程请求的计算,并报告了缺页错误,用户进程必然就中断了。这样的中断称之为缺页中断。在报告 Page Fault 之后,进程会从用户态切换到系统态,交由操作系统内核的 Page Fault Handler 处理缺页错误。
    • 1.3.缺页错误的分类和处理
      • 分类:
        • 硬缺页错误(Hard Page Fault)
        • 软缺页错误(Soft Page Fault)
      • 基本来说,缺页错误可以分为两类:硬缺页错误(Hard Page Fault)和软缺页错误(Soft Page Fault)。这里,前者又称为主要缺页错误(Major Page Fault);后者又称为次要缺页错误(Minor Page Fault)。当缺页中断发生后,Page Fault Handler 会判断缺页的类型,进而处理缺页错误,最终将控制权交给用户态代码。
      • 一:若是此时物理内存里,已经有一个页帧正是此时 CPU 请求的内存页,那么这是一个软缺页错误;
        • 于是,Page Fault Hander 会指示 MMU 建立相应的页帧到页的映射关系。这一操作的实质是进程间共享内存——比如动态库(共享对象),比如 mmap 的文件。
      • 二:若是此时物理内存中,没有相应的页帧,那么这就是一个硬缺页错误;
        • 于是 Page Fault Hander 会指示 CPU,从已经打开的磁盘文件中读取相应的内容到物理内存,而后交由 MMU 建立这份页帧到页的映射关系。
      • 区别:
        • 不难发现,软缺页错误只是在内核态里轻轻地走了一遭,而硬缺页错误则涉及到磁盘 I/O。因此,处理起来,硬缺页错误要比软缺页错误耗时长得多。这就是为什么我们要求高性能程序必须在对外提供服务时,尽可能少地发生硬缺页错误。
      • 补充:
        • 除了硬缺页错误和软缺页错误之外,还有一类缺页错误是因为访问非法内存引起的。前两类缺页错误中,进程尝试访问的虚存地址尚为合法有效的地址,只是对应的物理内存页帧没有在物理内存当中。后者则不然,进程尝试访问的虚存地址是非法无效的地址。比如尝试对 nullptr 解引用,就会访问地址为 0x0 的虚存地址,这是非法地址。此时 CPU 报出无效缺页错误(Invalid Page Fault)。操作系统对无效缺页错误的处理各不相同:Windows 会使用异常机制向进程报告;*nix 则会通过向进程发送 SIGSEGV 信号(11),引发 内存转储
    • 1.4.缺页错误的原因
      • 之前提到,物理内存中没有 CPU 所需的页帧,就会引发缺页错误。这一现象背后的原因可能有很多。
      • 情况1:
        • 例如说,进程通过 mmap 系统调用,直接建立了磁盘文件和虚拟内存的映射关系。然而,在 mmap 调用之后,并不会立即从磁盘上读取这一文件。而是在实际需要文件内容时,通过 CPU 触发缺页错误,要求 Page Fault Handler 去将文件内容读入内存。
      • 情况2:
        • 又例如说,一个进程启动了很久,但是长时间没有活动。若是计算机处在很高的内存压力下,则操作系统会将这一进程长期未使用的页帧内容,从物理内存转储到磁盘上。这个过程称为换出(swap out)。在 *nix 系统下,用于转储这部分内存内容的磁盘空间,称为交换空间;在 Windows 上,这部分磁盘空间,则被称为虚拟内存,对应磁盘上的文件则称为页面文件。在这个过程中,进程在内存中保存的任意内容,都可能被换出到交换空间:可以是数据内容,也可以是进程的代码段内容。
  • 2.观察缺页错误 .

  • 3.一个硬缺页错误导致的问题

    • 多名组内成员共享一台调研机器
      • 一方面,因为公用机器的人很多,必然造成内存压力大,从而存在大量换出的内存;
      • 另一方面,新启动的进程,会逐帧地扫描文件;
      • 这样一来,新启动的进程,就必须在极大的内存压力下,不断逼迫系统将其它进程的内存换出,而后换入自己需要的内存,不断进行磁盘 I/O;
      • 故此,新启动的进程会耗费大量时间进行不必要的磁盘 I/O。

2019年5月5日 下午5:44

Linux 相关信息速查表 | 始终
Linux思维导图整理

系统相关

1
2
3
4
5
6
7
8
9
10
lsb_release -a              # 查看操作系统版本
head -n 1 /etc/issue # 查看操作系统版本
cat /proc/version # 查看操作系统内核信息
uname -a # 查看操作系统内核信息、CPU 信息
cat /proc/cpuinfo # 查看 CPU 信息
hostname # 查看计算机名字
env # 列出环境变量
lsmod # 列出加载的内核模块
uptime # 查看系统运行时间、负载、用户数量
cat /proc/loadavg # 查看系统负载

内存与外存

1
2
3
4
5
6
7
8
9
10
free -m                     # 查看物理内存和交换区的使用情况
grep MemTotal /proc/meminfo # 查看内存总量
grep MemFree /proc/meminfo # 查看空闲内存总量
df -h # 查看各分区使用情况
fdisk -l # 查看所有分区
swapon -s # 查看所有交换分区
hdparm -i /dev/hda # 查看 IDE 磁盘的参数
dmesg | grep IDE # 查看系统启动时 IDE 磁盘的状态
mount | column -t # 查看各分区的挂载状态
du -sh <目录名> # 查看指定目录的大小

网络状态

1
2
3
4
5
6
ifconfig                    # 查看所有网络接口的属性
iptables -L # 查看 iptables 防火墙
route -n # 查看本机路由表
netstat -lntp # 查看所有监听端口
netstat -antp # 查看所有已建立的连接
netstat -s # 查看网络统计信息

用户状态相关

1
2
3
4
5
w                           # 查看活动用户以及他们在做什么
who # 查看活动用户
id <用户名> # 查看用户的 ID、组信息
cut -d: -f1 /etc/passwd # 查看系统中所有用户
cut -d: -f1 /etc/group # 查看系统所有组

进程状态相关

1
2
ps -ef                      # 查看所有进程
top # 动态显示进程状态

2019年5月5日 下午3:34

程序员的自我修养(八):使用 JProbe 调试 Linux 内核 | 始终
程序员的自我修养(七):内存缺页错误 | 始终
程序员的自我修养(六):保护线程间的共享数据 | 始终
程序员的自我修养(五):C++ 多线程编程初步 | 始终
程序员的自我修养(四):C++ 与并发的基本问题 | 始终
程序员的自我修养(三):fork() 安全 | 始终
程序员的自我修养(二):操作系统、进程与线程
程序员的自我修养(一):计算机硬件架构的发展

2019年5月5日 下午3:23

程序员的自我修养(二):操作系统、进程与线程

  1. 这篇文章最终要的就是举例说明了过度优化的问题,对操作系统写的并不是很好

  2. 同步是一种规则,而锁则是实现这种规则的具体方法

    1. 同步,指的是多线程程序里,多个线程不得同时对某一共享变量进行访问
  3. 锁,所作为一种同步手段,是非常强的。但是,这种强,仅限于逻辑层面。在实际情况中,编译器优化、CPU 动态调度,都有可能打破锁对于同步的保护。这时候,这些优化就变成了过度优化

    1. cpu动态调度:
      1. 程序在执行的过程中,出于效率的考量,两个(在当前线程中)没有依赖的指令可能会调换顺序执行
      2. eg:构造函数的执行和指针的赋值是互不依赖的
        1. 单例模式
    2. 编译器优化
      1. 编译器优化可能会破坏逻辑上的线程安全
      2. eg:如果线程 1 在这之后会多次使用变量x,那么编译器可能会将x自增后的值存放在寄存器中,暂不写回

2019年5月5日 下午3:03
【译】Linux概念架构的理解 - 简书

  1. 当提到ARM、机组等知识时,总是下意识的这就是硬件知识,这是不对的
    1. 完全没有软件的硬件就是一堆废铁
    2. 指令其实就是软件
  2. 核心的理解、出发点。理解了这两个点,对操作系统就一个一个整体的正确的认识了
    1. 虚拟化(抽象)
    2. 多任务处理
      1. 多任务处理有更多的学习价值,有更多可以钻研的东西
  3. 从他们的依赖关系可以看出,各个module之间相互调用(双向的数据调用),这时就不肯会有上下级的分层关系
    1. 这不是他们不想分层,而是没法分层
  4. 我对可扩展性的理解:
    1. 可扩展性就是说:这部分,我们可以直接换掉,也可以理解成模块化
    2. 可扩展性的同时会出现代码的冗余,也就是说:我们要换也只能换这整个模块。这种冗余我觉得是可以忽略的,站在整体的宏观角度,其实已经有很多很多的模块,换一个模块,对整体来说成本是很小的
    3. 学习linux这些知识,由于linux的整体架构特别的可扩展、模块化。那么,我们为了解决一个问题,就没必要把整体系统了解,我们只需要机械化的步骤就可以了
      1. 这也说明,linux没人带的情况下不要自己瞎学

2019年4月29日 下午8:13

参考:

B站:降维算法-PCA主成分分析
矩阵特征值和特征向量详细计算过程 - Junerror的博客 - CSDN博客

核心总结:

  1. PCA的出发点很简单,就是基于方差。巧妙的是,它这里使用了很多他及没有走建模的思路,已没有使用优化的思路(极值求解)的思路,而是采用的矩阵分解的思路解决一个看似求极值的问题(最大方差)的问题。
  2. 要理解这种方法,关键是要理解特征向量就可以表示新基在旧坐标系的坐标,那么我们就可以直接通过特征向量点积的方式,让旧数据映射到新的基(坐标系)中

初始出发点和目标:

  1. 基于方差
    1. 如果数据方差大,那么说明他们之间的距离远,这样就能够更加明显的分类
    2. 所以,我们的目标:找到能让数据映射之后方差最大的坐标系

目标1:

  1. 方差大
  2. 协方差小
    1. 协方差有三个重要的知识点:
      1. 公式:
      2. 出发点:我理解他就和人为定义loss function是一样的,用来衡量两个特征列之间的距离
        1. 这样定义距离的原因,我认为是:这个距离是可以直接通过矩阵运算来求解的,因为它方便
      3. 举例子:

目标2:

  1. 根据目标1,我们将问题描述为数学语言
    1. 协方差矩阵,就是我们描述的结果,因为他其中包含了方差和协方差这两个概念
  2. 我们的目标就变成了:协方差矩阵对角化
    1. 这里要使用考研最后一道题的思路,来已知矩阵A,求解特征向量和特征值
      1. 矩阵特征值和特征向量详细计算过程
    2. 求出的结果:
      1. 一个特征向量表示:一个新基
        1. 这基指的是:在旧坐标系中,这个新基的坐标
        2. 用法:旧数据 * 新基(*代表:点积),求出的是旧数据在新坐标系下的坐标
          1. 注意:这里的新基要归一为单位向量
      2. 多个特征向量表示:多个新基
        1. 表示:旧数据在多个新基上进行映射(点积)
        2. 使用几个特征向量就表示降到了几维
          1. 最多保持原维数
      3. 特征值在这里可以理解成:对应特征向量的重要程度,我们挑取最终要部分来做到降维的效果

遗留问题:

  1. 如何证明求出的特征向量就是新基的坐标?
  2. 对协方差矩阵的求出的特征向量和特征值,等价于对原始数据的?

我截了几张比较重要的地方




核心方法:

2019年4月29日 下午7:33

  1. 给定一个矩阵A,我们就已知的他的特征向量特征值
  2. 可以用来:
    1. 压缩:
      1. 直观的表现就是旋转坐标系,让映射后的数据方差大、协方差小
      2. 可以用来改变原始的数据(A)
    2. 矩阵当成一种函数来理解。
      1. 这个函数主要有两个性质
        1. 性质1:特征向量表方向
        2. 性质2:特征值表步长
      2. 这样理解有什么用?可以理解下面这幅图在说什么
      3. 参考:
        1. 如何理解矩阵特征值?
        2. 如何理解矩阵乘法?

2019年4月28日 下午12:58

深度学习的发展:

深度学习有多深?学了究竟有几分?(一)

  1. 人工智能研究的方向之一, 是以所谓 “专家系统” 为代表的, 用大量 “如果-就” (If - Then) 规则定义的, 自上而下的思路.
  2. 人工神经网络 ( Artifical Neural Network),标志着另外一种,自下而上的思路.
  3. 一个计算模型,要划分为神经网络,通常需要大量彼此连接的节点 (也称 ‘神经元’),并且具备两个特性:
    1. 每个神经元, 通过某种特定的输出函数 (也叫激励函数 activation function),计算处理来自其它相邻神经元的加权输入值.
    2. 神经元之间的信息传递的强度,用所谓加权值来定义,算法会不断自我学习,调整这个加权值.
      1. 学习的就是这个信息传递的强度
    3. 在此基础上,神经网络的计算模型, 依靠大量的数据来训练, 还需要:
      1. 成本函数 (cost function)
        1. 用来定量评估根据特定输入值, 计算出来的输出结果,离正确值有多远,结果有多靠谱.
      2. 学习的算法 ( learning algorithm )
        1. 这是根据成本函数的结果, 自学, 纠错, 最快地找到神经元之间最优化的加权值.
  4. 用小明,小红和隔壁老王们都可以听懂的语言来解释, 神经网络算法的核心就是

计算, 连接, 评估, 纠错, 疯狂培训

深度学习有多深,学了究竟有几分?(二)

  1. 分布式表征 (Distributed Representation), 是神经网络研究的一个核心思想.
    1. 大脑对于事物和概念的记忆, 不是存储在某个单一的地点,而是像全息照片一样, 分布式地, 存在于一个巨大的神经元的网络里.
      1. 它的意思是,当你表达一个概念的时候,不是用单个神经元,一对一地存储定义; 概念和神经元是多对多的关系: 一个概念可以用多个神经元共同定义表达, 同时一个神经元也可以参与多个不同概念的表达.
      2. 举个最简单的例子, 一辆 “大白卡车”,如果分布式地表达,一个神经元代表大小,一个神经元代表颜色,第三个神经元代表车的类别. 三个神经元同时激活时,就可以准确描述我们要表达的物体.
    2. 分布式表征,和传统的局部表征 (localized representation) 相比,存储效率高很多. 线性增加的神经元数目,可以表达指数级增加的大量不同概念.
      1. 分布式表征的另一个优点是,即使局部出现硬件故障,信息的表达不会受到根本性的破坏.
  2. 反向传播算法
    1. 传统的感知器用所谓 “梯度下降”的算法纠错时,耗费的计算量,和神经元数目的平方成正比.
    2. 1986年七月, Hinton 和 David Rumelhart 合作在自然杂志上发表论文, “Learning Representations by Back-propagating errors”, 第一次系统简洁地阐述,反向传播算法在神经网络模型上的应用.
    3. 反向传播算法,把纠错的运算量, 下降到只和神经元数目本身成正比.
    4. 反向传播算法,通过在神经网络里增加一个所谓隐层 (hidden layer), 同时也解决了感知器无法解决异或门 (XOR gate) 的难题.
  3. 支持向量机 (Support Vector Machine)
    1. 早在1963年, Vapnik 就提出了 支持向量机 (Support Vector Machine) 的算法.支持向量机, 是一种精巧的分类算法.
    2. 除了基本的线性分类外,在数据样本线性不可分的时候, SVM 使用所谓 “核机制” (kernel trick) 的非线性映射算法, 将线性不可分的样本转化到高维特征空间 (high-dimensional feature space),使其线性可分.
    3. Vapnik 的观点是, SVM,非常精巧地在 “容量调节” (Capacity Control)上 选择一个合适的平衡点, 而这是神经网络不擅长的.
    4. 什么是 “容量调节”?
      1. 举个简单的例子: 如果算法容量太大,就像一个记忆力极为精准的植物学家, 当她看到一颗新的树的时候,由于这棵树的叶子和她以前看到的树的叶子数目不一样,所以她判断这不是树; 如果算法容量太小,就像一个懒惰的植物学家,只要看到绿色的东西,都把它叫做树.
    5. 严乐春的观点是, 用有限的计算能力,解决高度复杂的问题,比”容量调节”更重要. 支持向量机,虽然算法精巧,但本质就是一个双层神经网络系统.它的最大的局限性,在于其”核机制”的选择 . 当图像识别技术需要忽略一些噪音信号时,卷积神经网络的技术,计算效率就比 SVM 高的多.
  4. 神经网络的计算,在实践中还有另外两个主要问题:
    1. 第一, 算法经常停止于局部最优解,而不是全球最优解. 这好比”只见树木,不见森林”.
    2. 第二, 算法的培训,时间过长时,会出现过度拟合 (overfit),把噪音当做有效信号.

深度学习有多深?学了究竟有几分(三)

  1. 有哲人对蛮力有另外一个诠释: “Quantity is Quality”.

深度学习有多深? 学了究竟有几分? (四)

  1. 受限玻尔兹曼机(RBM)

深度学习有多深? 学了究竟有几分? (五)

  1. 主流学术界的研究者,大多注重于在算法上的渐进式提高, 而轻视计算速度和用于训练的数据规模的重要性.

深度学习有多深?学了究竟有几分?(六)

  1. 从生存所需的能量角度去理解能量函数:
    1. 神经网络的模型中,通过所谓激励函数 (activation function), 根据上一层神经元输入值来计算输出值
    2. 最典型的传统激励函数,sigmoid function, 输出值在 0 和 1 之间, 也就意味着神经元平均下来, 每时每刻都在使用一半的力量.
  2. RELU
    1. 2011 年, 加拿大的蒙特利尔大学Yoshua Bengio

深度学习有多深?学了究竟有几分?(七)

  1. 解决 过度拟合 (overfitting).
    1. 2012年七月, Hinton 教授一种新的称为”丢弃” (Dropout) 的算法.
      1. 丢弃算法的具体实施,是在每次培训中, 给每个神经元一定的几率 (比如 50%),假装它不存在,计算中忽略不计.
      2. 从一个角度看, 丢弃算法,每次训练时使用的是不同架构的神经网络 (因为每次都有部分神经元装死),最后训练出来的东西,相当于不同架构的神经网络模型的平均值.
      3. 从生物的有性繁殖角度看,丢弃算法,试图训练不同的小部分神经元,通过多种可能的交配组合,获得接近理想值的答案.

深度学习有多深?学了究竟有几分?(八)

  1. 2012年,Hinton 教授和他的两个研究生 Alex Krizhevsky, Illya Sutskever 将深度学习的最新技术用到 ImageNet 的问题上.
    深度学习有多深?学了究竟有几分?(九)
  2. Hinton 教授的父亲 Howard Hinton
    深度学习有多深?学了究竟有几分?(十)
  3. 2015何凯明深度残余学习”的概念, 借鉴了图像识别中的”残余向量”的概念.

深度学习有多深? 学了究竟有几分? (十一)-

  1. 迄今为止我们讨论的神经网络模型, 都属于一种叫做前馈网络 (feedforward network) 的东西. 简而言之, 前馈网络, 信息从底层不断往前单向传输,故而得名.
  2. RNN
    1. RNN (Recurrent Neural Network), 也称循环神经网络, 多层反馈神经网络, 则是另一类非常重要的神经网络.
    2. 本质上, RNN 和前馈网络的区别是,:它可以保留一个内存状态的记忆, 来处理一个序列的输入, 这对手写字的识别, 语音识别和自然语言处理上, 尤为重要.
    3. 从另外一个角度看, 传统神经网络, 输入和输出的向量, 长度都是固定的, 是简单的一对一的关系.
  3. 1997,LSTM
    1. 如果”忘记历史意味着背叛”, 那么对于没有使用 LSTM 的神经网络, “忘记历史则意味着迷茫和不知所措”。”深度残余学习”, 本质上是借鉴了 LSTM 模型的思路, 但是去掉了里面的 forget gate (遗忘之门) 这个概念而已.

自然语言:

深度学习有多深?学了究竟有几分?(十二)自然语言

  1. 马尔科夫模型
    1. 马尔科夫模型, 是一个概率的模型. 其核心思想, 就是一个系统, 下一个时间点的状态, 只取决于当前的状态, 而和更早的时间点 (昨天, 前天, 大前天)的状态无关.
  2. 高斯混合模型
    1. 就是把现实中的数据, 分解成一些基于高斯概率密度函数 (又称正态分布)的叠加
  3. 高斯混合模型的硬伤,
    1. 是在部分应用场景中, 试图用过于复杂的统计模型,拟合本质上很简单的数据
      深度学习有多深?学了究竟有几分?(十三)
  4. 2015年五月, 谷歌宣布, 依靠 RNN/LSTM 相关的技术, 谷歌语音 (Google Voice) 的单词错误率降到了8% (正常人大约 4%).
    深度学习有多深?(十四)循环神经网络和言情小说
  5. 循环神经网络 (RNN)的本质,
    1. 是可以处理一个长度变化的序列的输出和输入 (多对多). 广义的看, 如果传统的前馈神经网络做的事, 是对一个函数的优化 (比如图像识别). 那么循环神经网络做的事, 则是对一个程序的优化,应用空间宽阔得多.
  6. 长短期记忆 (LSTM)的架构, 使有用的历史信息, 可以保留下来,很久以后仍然可以读取.
    深度学习有多深?(十五)自然语言的困惑

计算力:

深度学习有多深?(十六)再论计算速度的蛮力
深度学习有多深?(十七)衡量GPU的计算能力

  1. 衡量GPU的计算能力