#yyds干货盘点# 进程相关技术原理

一卷旌收千骑虏,万全身出百重围。这篇文章主要讲述#yyds干货盘点# 进程相关技术原理相关的知识,希望能为你提供帮助。
1.进程和内存管理内核功用:进程管理、内存管理、文件系统、网络功能、驱动程序、安全功能等
?
什么是进程
Process: 运行中的程序的一个副本,是被载入内存的一个指令集合,是资源分配的单位
  进程ID(Process ID,PID)号码被用来标记各个进程
    UID、GID、和SELinux语境决定对文件系统的存取和访问权限
  通常从执行进程的用户来继承
  存在生命周期
进程创建:
init:第一个进程,从  CentOS7 以后为systemd
进程:都由其父进程创建,fork(),父子关系,CoW:Copy On Write
进程,线程和协程


协程由程序员来控制的

查看进程中的线程:
通过进程找到文件的路径



1.找到passwd的进程,判断他是单线程








进程结构

内核把进程存放在叫做任务队列(task list)的双向循环链表中,链表中的每一项都是类型为task_struct,称为进程控制块(Processing Control Block),PCB中包含一个具体进程的所有信息
?
进程控制块PCB包含信息:
  进程id、用户id和组id
  程序计数器
  进程的状态(有就绪、运行、阻塞)
  进程切换时需要保存和恢复的CPU寄存器的值
  描述虚拟地址空间的信息
  描述控制终端的信息
  当前工作目录
  文件描述符表,包含很多指向file结构体的指针
  进程可以使用的资源上限(ulimit –a命令可以查看)
  输入输出状态:配置进程使用I/O设备
2. 进程相关概念Page Frame: 页框,用存储页面数据,存储Page 4k

[root@c7-147 ~]#getconf -a |grep -i size
PAGESIZE4096
PAGE_SIZE4096
SSIZE_MAX32767
_POSIX_SSIZE_MAX32767
_POSIX_THREAD_ATTR_STACKSIZE200809
FILESIZEBITS64
POSIX_ALLOC_SIZE_MIN4096
POSIX_REC_INCR_XFER_SIZE
POSIX_REC_MAX_XFER_SIZE
POSIX_REC_MIN_XFER_SIZE4096
LEVEL1_ICACHE_SIZE32768
LEVEL1_ICACHE_LINESIZE64
LEVEL1_DCACHE_SIZE32768
LEVEL1_DCACHE_LINESIZE64
LEVEL2_CACHE_SIZE262144
LEVEL2_CACHE_LINESIZE64
LEVEL3_CACHE_SIZE12582912
LEVEL3_CACHE_LINESIZE64
LEVEL4_CACHE_SIZE0
LEVEL4_CACHE_LINESIZE0

3. 物理地址空间和虚拟地址空间MMU(它属于CPU):Memory Management Unit 负责虚拟地址转换为物理地址
程序在访问一个内存地址指向的内存时,CPU不是直接把这个地址送到内存总线上,而是被送到
MMU(Memory Management Unit),然后把这个内存地址映射到实际的物理内存地址上,然后通过总线再去访问内存,程序操作的地址称为虚拟内存地址
TLB(避免每次都通过MMU来计算,提高效率):Translation Lookaside Bu?er 翻译后备缓冲器,用于保存虚拟地址和物理地址映射关系的缓存
?
4. 用户和内核空间
5.   C代码和内存布局之间的对应关系
每个进程都包括5种不同的数据段
  代码段:用来存放可执行文件的操作指令,也就是说是它是可执行程序在内存中的镜像。代码段需
要防止在运行时被非法修改,所以只准许读取操作,而不允许写入(修改)操作——它是不可写的
  数据段:用来存放可执行文件中已初始化全局变量,换句话说就是存放程序静态分配的变量和全局变量
  BSS段:Block Started by Symbol”的缩写,意为“以符号开始的块,BSS段包含了程序中未初始化的全局变量,在内存中  bss段全部置零
  堆(heap):存放数组和对象,堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
  栈:栈是用户存放程序临时创建的局部变量,也就是说我们函数括弧“”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的后进先出特点,所以栈特别方便用来保存/恢复调用现场。可以把堆栈看成一个寄存、交换临时数据的内存区

6. 进程使用内存问题内存泄漏:Memory Leak
指程序中用malloc或new申请了一块内存,但是没有用free或delete将内存释放,导致这块内存一直处于占用状态
内存溢出:Memory Overflow
指程序申请了10M的空间,但是在这个空间写入10M以上字节的数据,就是溢出
内存不足:OOM
OOM 即  Out Of Memory,“内存用完了”,在情况在java程序中比较常见。系统会选一个进程将之杀死,在日志messages中看到类似下面的提示
Jul 10 10:20:30 kernel: Out of memory: Kill process 9527 (java) score 88 or sacrifice child
当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error,因为这个问题已经严重到不足以被应用处理)。
原因:
  给应用分配内存太少:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。
  应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。
使用的解决办法:
【#yyds干货盘点# 进程相关技术原理】1,限制java进程的max heap,并且降低java程序的worker数量,从而降低内存使用
2,给系统增加swap空间
设置内核参数(不推荐),不允许内存申请过量:
echo 2 > /proc/sys/vm/overcommit_memory
echo 80 > /proc/sys/vm/overcommit_ratio
echo 2 > /proc/sys/vm/panic_on_oom

Linux默认是允许memory overcommit的,只要你来申请内存我就给你,寄希望于进程实际上用不到那么多内存,但万一用到那么多了呢?Linux设计了一个OOM killer机制挑选一个进程出来杀死,以腾出部分内存,如果还不够就继续。也可通过设置内核参数  vm.panic_on_oom 使得发生OOM时自动重启系统。这都是有风险的机制,重启有可能造成业务中断,杀死进程也有可能导致业务中断。所以Linux 2.6之后允许通过内核参数  vm.overcommit_memory 禁止memory overcommit。
vm.panic_on_oom 决定系统出现oom的时候,要做的操作。接受的三种取值如下:
0 - 默认值,当出现oom的时候,触发oom killer

1 - 程序在有cpuset、memory policy、memcg的约束情况下的OOM,可以考虑不panic,而是启动OOM killer。其它情况触发 kernel panic,即系统直接重启

2 - 当出现oom,直接触发kernel panic,即系统直接重启

vm.overcommit_memory 接受三种取值:
0 – Heuristic overcommit handling. 这是缺省值,它允许overcommit,但过于明目张胆的overcommit会被拒绝,比如malloc一次性申请的内存大小就超过了系统总内存。Heuristic的意思是“试探式的”,内核利用某种算法猜测你的内存申请是否合理,它认为不合理就会拒绝overcommit。

1 – Always overcommit. 允许overcommit,对内存申请来者不拒。内核执行无内存过量使用处理。使

用这个设置会增大内存超载的可能性,但也可以增强大量使用内存任务的性能。

2 – Don’t overcommit. 禁止overcommit。 内存拒绝等于或者大于总可用 swap 大小以及

overcommit_ratio 指定的物理 RAM 比例的内存请求。如果您希望减小内存过度使用的风险,这个设置就是最好的。

Heuristic overcommit算法:
单次申请的内存大小不能超过以下值,否则本次申请就会失败。
free memory + free swap + pagecache的大小  + SLAB
vm.overcommit_memory=2 禁止overcommit,那么怎样才算是overcommit呢?
kernel设有一个阈值,申请的内存总数超过这个阈值就算overcommit,在/proc/meminfo中可以看到这个阈值的大小:
grep -i commit /proc/meminfo
CommitLimit:5967744 kB
Committed_AS: 5363236 kB

CommitLimit 就是overcommit的阈值,申请的内存总数超过CommitLimit的话就算是overcommit。
此值通过内核参数vm.overcommit_ratio或vm.overcommit_kbytes间接设置的,公式如下
CommitLimit = (Physical RAM * vm.overcommit_ratio / 100) + Swap
vm.overcommit_ratio 是内核参数,缺省值是50,表示物理内存的50%。如果你不想使用比率,也可以直接指定内存的字节数大小,通过另一个内核参数  vm.overcommit_kbytes 即可;如果使用了huge pages,那么需要从物理内存中减去,公式变成:
CommitLimit = ([total RAM] – [total huge TLB RAM]) * vm.overcommit_ratio / 100 + swap

/proc/meminfo中的  Committed_AS 表示所有进程已经申请的内存总大小,(注意是已经申请的,不是已经分配的),如果  Committed_AS 超过  CommitLimit 就表示发生了  overcommit,超出越多表示  overcommit 越严重。Committed_AS 的含义换一种说法就是,如果要绝对保证不发生OOM (out of memory) 需要多少物理内存。
[root@c7-147 955]#cat /proc/sys/vm/panic_on_oom
0
You have new mail in /var/spool/mail/root
[root@c7-147 955]#cat /proc/sys/vm/overcommit_memory
0
[root@c7-147 955]#cat /proc/sys/vm/overcommit_ratio
50
[root@c7-147 955]#grep -i commit /proc/meminfo
CommitLimit:3031492 kB
Committed_AS:280996 kB


    推荐阅读