zoukankan      html  css  js  c++  java
  • linux 进程管理和内存分配

    1、进程相关概念

      进程:正在运行中的程序

      内核功用:进程管理、文件系统、网络功能、内存管理、驱动程序、安全功能等

      Process:运行中的程序的一个副本,是被载入内存的一个指令集合
        进程 ID(Process ID,PID)号码被用来标记各个进程
        通常从执行进程的用户来继承,存在生命周期

      task struct 任务结构表:Linux 内核存储进程信息的数据结构格式

      task list 任务列表:多个任务的 task struct 组成的链表

      进程创建:
        都由其父进程创建,父好关系,CoW(写时复制,不发生改变时父子都指向同一文件;发生改变时,则复制)
        init:第一个进程(centos6:init,centos7:systemd)
        守护进程:随着计算机的开启、关闭而随之开启、关闭。

    2、进程,线程和协程:

      

      注:一个进程里至少有一个线程;线程之间由操作系统进行调度,包括进程中使用的资源也由操作系统进行调度;协程相当于线程中的语句块,由线程控制。

    3、Page Frame:页框,用存储页面数据,存储 Page,每个进程要使用的分配空间
      虚拟内存(线性内存):进程运行的时候以为自己拥有了全部的内存空间
      物理地址空间和线性地址空间:
        MMU:负责转换线性和物理地址(虚拟内存和物理内存)
        TLB:翻译后备缓冲器,用于保存虚拟地址和物理地址映射关系的缓存
        LRU:近期最少使用算法,释放内存

    4、用户空间和内核空间:

      

    5、进程之间基本状态和转换:

      

      创建状态:进程在创建时需要申请一个空白 PCB(进程控制块),向其中填写控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态。
      就绪状态:进程已准备好,已分配到所需资源,只要分配到 CPU 就能够立即运行。
      执行状态:进程处于就绪状态被调度后,进程进入执行状态。
      阻塞状态:正在执行的进程由于某些事件(I/O 请求,申请缓存区失败)而暂时无法运行,进程受到阻塞,在满足请求时进入就绪状态等待系统调用。
      终止状态:进程结束,或出现错误,或被系统终止,进入终止状态,无法再执行。

      状态之间转换六种情况:
      运行 → 就绪:1,主要是进程占用 CPU 的时间过长,而系统分配给该进程占用 CPU 的时间是有限的;2,在采用抢先式优先级调度算法的系统中,当有更高优先级的进程要运行时,该进程就被迫让出 CPU,该进程便由执行状态转变为就绪状态。
      就绪 → 运行:运行的进程的时间片用完,调度就转到就绪队列中选择合适的进程分配 CPU。
      运行 → 阻塞:正在执行的进程因发生某等待事件而无法执行,则进程由执行状态变为阻塞状态如发生了 I/O 请求。
      阻塞 → 就绪:进程所等待的事件已经发生,就进入就绪队列。
      以下两种状态是不可能发生的:
      阻塞 → 运行:即使给阻塞进程分配 CPU,也无法执行,操作系统在进行调度时,不会从阻塞队列进行挑选,而是从就绪队列中选取。
      就绪 → 阻塞:就绪态根本就没有执行,谈不上进入阻塞态。

    6、IPC 进程间通信:
      同一主机:
        pipe 管道,一个写入管道文件,一个读(单向)
        socket 套接字文件,进程间交换数据(双工工作方式)
        signal 信号
        shm shared memory,共享内存
        semaphore 信号量,一种计数器,分配资源
      不同主机:
        socket ip 和端口号
        RPC 远程过程调用
        MQ 消息队列,如:Kafka , RabbitMQ,ActiveMQ

    7、进程优先级

      

      实时进程(realtime),基于 FIFO 先进先出或 RR 轮询
      非实时进程:nice 按时间片分配进程
      取 139 个队列,将相同优先级的放在一个队列中,运行一个时间片后从运行队列转至过期队列。轮回运行队列和过期队列互调,再运行。

      

      进程优先级:
    系统优先级:数字越小,优先级越高
    0-139:各有 140 个运行队列和过期队列
        实时优先级:99-0 值最大优先级最高
        nice 值:-20 到 19,对应系统优先级 100-139

      Big 0:时间复杂度,用时和规模的关系
        0(1),O(logn),O(n)线性,O(n^2)抛物线,O(2^n)

    8、进程状态:
      Linux 内核:抢占式多任务,按时间片分配任务
      进程类型:
        守护进程:daemon,在系统引|导过程中启动的进程,和终端无关进程
        前台进程:跟终端相关,通过终端启动的进程,用户执行命令等
        注意:两者可相互转化
      进程状态:
        运行态:running
        就绪态:ready
        睡眠态:
          可中断:interruptable
          不可中断:uninterruptable
        停止态:stopped,暂停于内存,但不会被调度,除非手动启动
        僵死态:zombie,结束进程,父进程结束前,子进程不关闭

    9、进程工具

    9.1 系统管理工具:
      进程的分类:
        CPU-Bound:CPU 密集型,非交互
          编译安装、大量计算等
        IO-Bound:IO 密集型,交互
          拷贝大文件等 DMA:直接内存访问
      Linux 系统状态的查看及管理工具:

    pstree,ps,pidof,pgrep,top,htop,glance,pmap,vmstat,dstat,kill,pkill,job,bg,fg,nohup

      Linux 系统各进程的相关信息均保存在 /proc/PID 目录下的各文件中

    9.2 进程管理工具 PS 详解:

    复制代码
    ps [OPTION]...
    支持三种选项:
      UNIX 选项 如-A -e
      BSD 选项 如 a
      GNU 选项 如--help
    
    选项:默认显示当前终端中的进程   a 选项包括所有终端中的进程   x 选项包括不链接终端的进程   u 选项显示进程所有者的信息(有效用户)   f 选项显示进程树,相当于--forest   k|--sort 属性对属性排序,属性前加-表示倒序   o 属性...选项显示定制的信息 pid、cmd、%cpu、%mem   L 显示支持的属性列
    复制代码
    复制代码
    ps axo pid,%cpu,%mem,tty k %cpu
      -C cmdlist 指定命令,多个命令用,分隔,ps -C dd
      -L 显示线程
      -e 显示所有进程,相当于-A
      -f 显示完整格式程序信息
      -F 显示更完整格式的进程信息
      -H 以进程层级格式显示进程相关信息
      -u userlist 指定有效的用户 ID 或名称
      -U userlist 指定真正的用户 ID 或名称
      -g gid 或 groupname 指定有效的 gid 或组名称
      -G gid 或 groupname 指定真正的 gid 或组名称
      -p pid 显示指 pid 的进程
      --ppid pid 显示属于 pid 的子进程
      -M 显示 SELinux 信息,相当于 Z
    复制代码
    复制代码
    PS 输出属性:
      VSZ:Virtual memory SiZe,虚拟内存集,线性内存
      RSS:ReSident Size,常驻内存集
      STAT:进程状态
      R:running
      S:interruptable sleeping,可中断的休眠
      D:uninterruptable sleeping,不可中断的休眠
      T:stopped,停止态
      Z:zombie,僵尸态
      +:前台进程
      |:多线程进程
      L:内存分页并带锁
      N:低优先级进程
      <:高优先级进程
      s:session leader,会话 (子进程)发起者
    复制代码
    复制代码
    ps 优先级选项和常用组合:
      ni:nice 值
      pri:priority 优先级,和系统优先级相反
      psr:processor CPU 编号,CPU(一级二级,三级[共享]缓存)
        更换 CPU 缓存失效,解决:绑定进程和 CPU
        taskset -p [进程 ID],查看,命令显示和 CPU 核数不一样[二进制]
        tackset -cp 1 [进程 ID],绑定在 1 号 CPU 上 0,4 0-4 等
        pidof dd,查看 dd 命令的进程编号
      rtprio:实时优先级
    # 示例:
      ps axo pid,cmd,psr,ni,pri,rtprio
    # 常用组合:
      aux
      -ef
      -eFH
      -eo pid,tid,class,rtprio,ni,pripsr,pcpu,stat,comm
      axo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm
    nice -n 10 ping 192.168.129.142     # 以指定优先级运行该命令
    renice     # 更改优先级
    复制代码

      PS示例:

    复制代码
    # 列出有效组名称(或会话)所拥有的所有进程
    ps -fg mysql
    ps -fg 27
    
    # 显示指定的进程 ID 对应的进程 ps -fp 1234
    # 以父进程 ID 来显示其下所有的进程,如显示父进程为 1234 的所有进程 ps -f –ppid 1234
    # 显示指定 PID 的多个进程 ps -fp 1234,1236,1264
    # 要按 tty 显示所属进程 ps -ft pts/0
    # 自定义格式显示文件系统组,ni 值开始时间和进程的时间 ps -p 1234 -o pid,ppid,fgroup,ni,lstart,etime
    # 使用其 PID 查找进程名称 ps -p 1234 -o comm=
    # 要使用其名称选择特定进程,显示其所有子进程 ps -C sshd,bash
    # 查找指定进程名所有的所属 PID,在编写需要从 std 输出或文件读取 PID 的脚本时这个参数很有用 ps -C httpd,sshd -o pid=
    # 检查一个进程的执行时间 ps -eo comm,etime,user | grep nginx
    # 查找占用最多内存和 CPU 的进程 ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head
    # 显示安全信息 ps-eM ps --context
    # 使用以下命令以用户定义的格式显示安全信息 ps -eo euser,ruser,suser,fuser,f,comm,label
    # 使用 watch 实用程序执行重复的输出以实现对就程进行实时的监视,如下面的命令显示每秒钟的监视 watch -n 1 'ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem| head'
    复制代码

      搜素进程:

    复制代码
    最灵活:ps 选项 | 其它命令
    按预定义的模式:pgrep
    pgrep [options] pattern
      -u uid: effective user,生效者
      -U uid: realuser,真正发起运行命令者
      -t terminal:与指定终端相关的进程
         pgrep -t pts/1
      -l:显示进程名
      -a:显示完整格式的进程名
      -P pid:显示指定进程的子进程
    
    按确切的程序名称查询进程 ID: /sbin/pidof   pidof bash
    复制代码

    9.3 top 详解

    复制代码
    top:有许多内置命令
      排序:
        P:以占据的 CPU 百分比,%CPU
        M:占据内存百分比,%MEM
        T:累积占据 CPU 时长,TIME+
    
      首部信息显示:     uptime 信息: |命令     tasks 及 cpu 信息: t 命令     cpu 分别显示: 1 (数字)     memory 信息: m 命令     退出命令: q     修改刷新时间间隔: s     终止指定进程: k     保存文件: W
      栏位信息简介     us:用户空间     sy:内核空间     ni:调整 nice 时间     id:空闲     wa:等待 IO 时间     hi:硬中断     si:软中断(模式切换)     st:虚拟机偷走的时间
      选项:     -d # 指定刷新时间间隔,默认为 3 秒     -b 全部显示所有进程     -n # 刷新多少次后退出     -H 线程模式,示例:top -H -p `pidof mysqld`
    复制代码

    9.4 htop 详解

    复制代码
    htop 命令:EPEL 源
      选项:
        -d #:指定延迟时间;
        -u UserName:仅显示指定用户的进程
        -s COLUME:以指定字段进行排序
    
      子命令:     s:跟踪选定进程的系统调用     |:显示选定进程打开的文件列表     a:将选定的进程绑定至某指定 CPU 核心     t:显示进程树
    复制代码

    10、内存管理工具

    10.1 free 命令详解

    复制代码
    内存空间使用状态:
    free [OPTION]
      -b 以字节为单位
      -m 以 MB 为单位
      -g 以 GB 为单位
      -h 易读格式
      -0 不显示-/+ buffers/cache 行
      -t 显示 RAM + swap 的总和
      -s n 刷新间隔为 n 秒
      -c n 刷新 n 次后即退出
    cat /proc/sys/vm/drop_caches     # 缓存为 0,重定向一个 3 进去清理缓存
    复制代码

    10.2 内存工具 vmstat

    复制代码
    vmstat 命令:虚拟内存信息
    vmstat [options] [delay [count]]
    vmstat 2 5     # 2 秒执行一次,执行 5 次退出
    
    procs:   r:可运行(正运行或等待运行)进程的个数,和核心数有关   b:处于不可中断睡眠态的进程个数(被阻塞的队列的长度) memory:   swpd:交换内存的使用总量   free:空闲物理内存总量   buffer:用于 buffer 的内存总量   cache:用于 cache 的内存总量 swap:   si:从磁盘交换进内存的数据速率(kb/s)   so:从内存交换至磁盘的数据速率(kb/s) io:   bi:从块设备读入数据到系统的速率(kb/s)   bo:保存数据至块设备的速率 system:   in:interrupts 中断速率,包括时钟   cs:context switch 进程切换速率 cpu:   us:Time spent running non-kernel code   sy:Time spent running kernel code   id:Time spent idle. Linux 2.5.41 前,包括 IO-wait time.   wa:Time spent waiting for IO.2.5.41 前 ,包括 in idle.   st:Time stolen from a virtual machine. 2.6.11 前, unknown.
    选项: -s:显示内存的统计数据
    复制代码

    11、iostat 统计CPU和设备IO信息

    例:
    iostat 1 10

    12、iftop 显示带宽使用情况,epel源

    例:
    iftop -n -i eth1

    13、pmap 命令:进程对应的内存映射

    pmap [options] pid [..]
      -X:显示详细格式的信息
    例:
    pmap1

    14、系统监控工具

      glances 命令: EPEL 源

    复制代码
    glances [-bdehmnrsvyz1] [-B bind] [-c server] [-C conffile] [-p port] [-P password] [--password] [-t refresh] [-f file] [-o output]
    内建命令:
      a – 对进程自动排序
      c – 按 CPU 百分比对进程排序
      m – 按内存百分比对进程排序
      p – 按进程名字母顺序对进程排序
      i – 按读写频率(I/O)对进程排序
      d – 显示/隐藏磁盘 I/O 统计信息
      f – 显示/隐藏文件系统统计信息
      n – 显示/隐藏网络接口统计信息
      s – 显示/隐藏传感器统计信息
      y – 显示/隐藏硬盘温度统计信息
      l – 显示/隐藏日志(log)
      b – 切换网络 I/O 单位(Bytes/bits)
      w – 删除警告日志
      x – 删除警告和严重日志
      l – 切换全局 CPU 使用情况和每个 CPU 的使用情况
      h – 显示/隐藏这个帮助画面
      t – 以组合形式浏览网络 I/O
      u – 以累计形式浏览网络 I/O
      q – 退出('ESC' 和 'Ctrl&C' 也可以)
    常用选项:   -b:以 Byte 为单位显示网卡数据速率   -d:关闭磁盘 I/O 模块   -f /path/to/somefile:设定输入文件位置   -o {HTML|CSV} :输出格式   -m:禁用 mount 模块   -n:禁用网络模块   -t #:延迟时间间隔   -1 :每个 CPU 的相关数据单独显示
    C/S 模式下运行 glances 命令 服务器模式:   glances -s -B IPADDR   IPADDR:指明监听的本机哪个地址 客户端模式:   glances -c IPADDR   IPADDR:要连入的服务器端地址
    复制代码

      dstat 命令详解:系统资源统计

      dstat 是一个可以取代vmstat,iostat,netstat和ifstat这些命令的多功能产品。

    复制代码
    # yum install dsta    //安装
    
    dstat [-afv] [options..] [delay [count]
    常用命令选项:
      -c, --cpu:显示cpu相关信息;
      -C #,#,...,total
      -d, --disk:显示磁盘的相关信息
      -D sda,sdb,...,tobal
      -g:显示page相关的速率数据;
      -m:Memory的相关统计数据
      -n:Interface的相关统计数据;
      -p:显示process的相关统计数据;
      -r:显示io请求的相关的统计数据;
      -s:显示swapped的相关统计数据;        
      --tcp 
      --udp
      --raw 
      --socket           
      --ipc                 
      --top-cpu:显示最占用CPU的进程;
      --top-io:最占用io的进程;
      --top-mem:最占用内存的进程;
      --top-latency:延迟最大的进程;

    示例1:内存资源使用情况
    # dstat -glms --top-mem

    示例2:CPU资源使用情况
    # dstat -cyl --proc-count --top-cpu
    复制代码

      iotop 命令详解:

    复制代码
    iotop 命令是一个用来监视磁盘 I/O 使用状况的 top 类工具 iotop 具有与 top 相似的 UI,其中包括 PID、用户、I/O、进程等相关信息,可查看每个进程是如何使用 IO
    iotop 输出:
      第一行:Read 和 Write 速率总计
      第二行:实际的 Read 和 Write 速率
      第三行:参数如下:
        线程 ID (按 p 切换为进程 ID )
        优先级
        用户
        磁盘读速率
        磁盘写速率
        swap 交换百分比
        IO 等待所占的百分比
        线程/进程命令
    
    iotop 常用参数:   -o,--only 只显示正在产生I/O的进程或线程,除了传参,可以在运行过程中按o生效   -b,--batch 非交互模式,一般用来记录日志   -n NUM,--iter=NUM 设置监测的次数,默认无限。在非交互模式下很有用   -d SEC,--delay=SEC 设置每次监测的间隔,默认1秒,接受非整形数据例如1.1   -p PID,--pid=PID 指定监测的进程/线程   -u USER,--user=USER 指定监测某个用户产生的I/O   -P,--processes 仅显示进程,默认iotop显示所有线程   -a,--accumulated 显示累积的I/O,而不是带宽   -k,--kilobytes 使用kb单位,而不是对人友好的单位。在非交互模式下,脚本编程有用

    iotop 常用参数和快捷键:
      -t,--time   加上时间戳,非交互非模式
      -q, --quiet 禁止头几行,非交互模式,有三种指定方式
        -q      只在第一 次监测时显示列名
        -qq   永远不显示列名
        -qqq 永远不显示I/0汇总

    交互按键:
      left 和 right 方向键:改变排序
      r:反向排序
      0:切换至选项--only
      p:切换至--processes选项
      a:切换至--accumulated选项
      q:退出
      i:改变线程的优先级
    复制代码

      nload 查看网络实时吞吐量:

      nload 是一个实时监控网络流量和带宽使用情况,以数值和动态图展示进出的流量情况

    复制代码
    安装:yum -y install nload (EPEL 源)
    
    界面操作:
      上下方向键、左右方向键、enter 键或者 tab 键都就可以切换查看多个网卡的流量情况
      按 F2 显示选项窗口
      按 q 或者 Ctrl+C 退出 nload
    
    示例:   nload:默认只查看第一个网络的流量进出情况   nload eth0 eth1:在 nload 后面指定网卡,可以指定多个   设置刷新间隔:默认刷新间隔是 100 毫秒,可通过-t 命令设置刷新时间(单位是毫秒)     nload -t 500 eth0   设置单位:显示两种单位一种是显示 Bit/s、一种是显示 Byte/s,默认是以 Bit/s,也可不显示/s     -u h|b|k|m|g|H|B|K|M|G 表示的含义:h:auto,b:Bit/s,k:kBit/s,m:MBit/s,H:auto,B:Byte/s,K:kByte/s,M:MByte/s     nload-u M eth0
    复制代码

      lsof:list open files 查看当前系统文件的工具

    复制代码
    在 linux 环境下,一切皆文件,用户通过文件不仅可以访问常规数据还可以访问网络连接和硬件如传输控制协议(TCP)和用户数据报协议(UDP)套接字等,系统在后台都为该应用程序分配了一个文件描述符
    命令参数:
      -a:列出打开文件存在的进程
      -c<进程名>:列出指定进程所打开的文件
      -g:列出 GID 号进程详情
      -d<文件号>:列出占用该文件号的进程
      +d<目录>:列出目录下被打开的文件
      +D<目录>:递归列出目录下被打开的文件

    lsof示例:
    进程管理:
      查看由登陆用户启动而非系统启动的进程
        lsof /dev/pts/1
      指定进程号,可以查看该进程打开的文件
        Isof -p 9527
    文件管理:
      查看指定程序打开的文件
        Isof -c httpd
      查看指定用户打开的文件
        Isof -u root | more
      查看指定目录下被打开的文件
        lsof +D /var/log/
        lsof +d /var/log/
        参数 +D 为递归列出目录下被打开的文件,参数+d为列出目录下被打开的文件

    恢复删除文件:
    lsof | grep delete     # 查看打开文件(被误删除),看到进程编号,如:11863
    ll /proc/11863/fd     # 查看文件描述符,如 4(已被删除)
    cat /proc/11863/fd/4 > /data/m.txt     # 重定向找回文件

    查看所有网络连接:
      lsof -i -n
      lsof -i@127.0.0.1
      通过参数 -i 查看网络连接的情况,包括连接的ip、端口等以及一些服务的连接情况,例如:sshd等。也可以通过指定 ip 查看该 ip 的网络连接情况。
    查看端口连接情况:
      lsof -i :80 -n
      通过参数 -i:端口 可以查看端口的占用情况,-i参数还有查看协议,ip的连接情况等
    查看指定进程打开的网络连接:
      lsof -i -n -a -p 9527
      参数-i、-a、-p等,-i查看网络连接情况,-a查看存在的进程,-p指定进程
    查看指定状态的网络连接:
      lsof -n -P -i TCP -s TCP:ESTABLISHED
      -n:no host names,-P:no port names,-i TCP指定协议,-s指定协议状态通过多个参数可以清晰的查看网络连接情况、协议连接情况等
    复制代码

    15、进程管理工具

      kill 命令:向进程发送控制信号,以实现对进程管理每个信号对应一个数字,信号名称以 SIG 开头(可省略),不区分大小写

    复制代码
    显示当前系统可用信号:kill-I 或者 trap -l
    常用信号: man 7 signal
    0)           信号检查某个进程是否正常
    1) SIGHUP    无须关闭进程而让其重读配置文件
    2) SIGINT    中止正在运行的进程,相当于 Ctrl+C
    3) SIGQUIT   相当于 ctrl+
    9) SIGKILL   强制杀死正在运行的进程
    15) SIGTERM  终止正在运行的进程,默认
    18) SIGCONT  继续运行
    19) SIGSTOP  后台休眠
    指定信号的方法:
    (1)信号的数字标识:1,2,9
    (2)信号完整名称:SIGHUP
    (3)信号的简写名称: HUP
    
    示例: 先 ps aux 查到该进程 ID,kill -1 [进程 ID],发信号 kill -2 `pidof bc` # 中止 bc 程序 按 PID:kill [-SIGNAL] pid ...   kill -n SIGNAL pid   kill -S SIGNAL pid 按名称:killall [-SIGNAL] comm... # 例:killall httpd 按模式:pkill [options] pattern # 支持正则   -SIGNAL   -u uid:effective user,生效者   -U uid:realuser,真正发起运行命令者   -t terminal:与指定终端相关的进程   -l:显示进程名(pgrep 可用)   -a:显示完整格式的进程名(pgrep 可用)   -P pid:显示指定进程的子进程
    复制代码

    16、作业管理
    Linux 的作业控制:
      前台作业:通过终端启动,且启动后一直占据终端
      后台作业:可通过终端启动,但启动后即转入后台运行(释放终端)
    让作业运行于后台:
      (1)运行中的作业:Ctrl+z,停止状态
      (2)尚未启动的作业:COMMAND &
    后台作业虽然被送往后台运行,但其依然与终端相关;退出终端,将关闭后台作业。如果希望送往后台后,剥离与终端的关系:

    nohup COMMAND &> /dev/null &
    screen ; COMMAND

    查看当前终端所有作业: jobs
    作业控制:

    fg [[%]JOB_NUM]:把指定的后台作业调回前台
    bg [[%]JOB_ NUM]:让送往后台的作业在后台继续运行
    kill [%JOB_ NUM]:终止指定的作业
    killall -19 ping   # 19 信号将后台变为后台休眠状态
    killall -18 ping   # 18 信号将后台休眠变为后台执行

    并行运行:同时运行多个进程,提高效率

    复制代码
    方法 1:
    vi all.sh
    f1.sh&
    f2.sh&
    f3.sh&
    方法 2: (f1.sh&);(f2.sh&);(f3.sh&)
    方法 3: { f1.sh& f2.sh& f3.sh& } { ping 127.1& ping 127.2& ping 127.3& }
  • 相关阅读:
    MYSQL profiling分析语句
    进程状态与僵尸进程、孤儿进程
    Nginx跨域设置
    Redis的应用场景
    Nginx的作用
    cgi、fast-cgi和php-fpm的介绍(作用)
    CoreDump开启和Swoole Tracker 3.0配置
    好题总结
    Atcoder总结 Part III
    Atcoder总结 Part II
  • 原文地址:https://www.cnblogs.com/liliuguang/p/14345534.html
Copyright © 2011-2022 走看看