https://www.cnblogs.com/codelogs/p/16060443.html

原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。

简介#

这是Linux命令拾遗系列的第三篇,本篇主要介绍Linux中观测软件资源的命令,如ps、netstat、lsof,以及查看进程信息的宝库/proc目录。

本系列文章索引
Linux命令拾遗-入门篇
Linux命令拾遗-文本处理篇

系统资源常分为两类,一类是软件资源,如进程、线程、文件描述符、socket连接,偏开发视角,另一类是硬件资源,如CPU、内存、硬盘、网络,偏运维视角,而本章主要介绍Linux中与观测软件资源有关的命令。

ps查看进程相关信息#

相信ps命令大家也比较熟悉,主要是用来列出进程的,基本用法如下:

# 列出所有进程,-e表示列出所有进程,-f表示列出进程详细信息
$ ps -ef
# 也是列出所有进程,这是从BSD系统中保留过来的用法
$ ps aux
# -C java指定列出java进程
$ ps -fC java
# 列出java进程的pid,cpu使用率,内存使用率,-o指定列出的字段
$ ps -o pid,pcpu,pmem -C java
# 列出pid=328的进程,-p指定列出具体进程
$ ps -fp 328
# 列出前10个进程,cpu及内存倒序排序,--sort指定排序字段
ps aux --sort -pcpu,-pmem | head -n 10

上面用法在网上是很常见的,下面这些就不太常见了,但也很有用,如下:

  1. 查看进程启动时间。
    有时进程在非常频繁的重启,会导致系统CPU升高,可通过查看进程启动时间来推断是否刚重启了。
# 查看各java进程启动时间与已运行时长
$ ps -o lstart,etime -C java
STARTED ELAPSED
Fri Oct 22 20:33:31 2021 10:05
  1. 查看进程的线程数量。
    因为在Linux中,线程也叫做轻量级进程Light Weight Process(LWP),所以查看LWP数量就是线程数量。
# 查看各java进程的线程数量
$ ps -o pid,nlwp -C java
PID NLWP
2121 21
  1. 查看运行与阻塞状态的线程数量
    如果系统CPU使用率很高,我们可以通过top命令进一步找到是哪个进程占用cpu高,但在某些特殊场景下,可能会发现系统负载很高,但CPU使用率不高,这是由于Linux系统负载综合考察了系统中正在运行(R状态)的线程数量以及阻塞于IO(D状态)的线程数量,如果线程全阻塞于IO调用,就可能出现此现象。

这时可以尝试用下面方法统计各进程运行与阻塞线程数量,以判断是哪个进程导致了问题。

# 看进程运行及阻塞的线程数量之和,其中h表示不打印标题行,-L表示显示线程而不是进程
$ ps h -eLo s,pid | grep ^[RD] |sort|uniq -c|sort -nrk1

/proc目录#

在Linux系统中,进程的信息,都被虚拟到/proc目录中了,而ps命令不过是从这个目录中读取数量,并展示出来罢了。
/proc/397/就表示397这个进程相关信息的起始目录,如下:

$ ll /proc/397/
total 0
dr-xr-xr-x 2 work work 0 2021-10-17 21:41:53 attr
-r-------- 1 work work 0 2021-10-17 21:41:53 auxv
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 cgroup
-r--r--r-- 1 work work 0 2021-10-17 21:41:41 cmdline
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 comm
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 coredump_filter
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 cpuset
lrwxrwxrwx 1 work work 0 2021-10-17 21:41:53 cwd -> /home/work
-r-------- 1 work work 0 2021-10-17 21:41:53 environ
lrwxrwxrwx 1 work work 0 2021-10-17 21:41:53 exe -> /usr/bin/ncat
dr-x------ 2 work work 0 2021-10-17 21:41:53 fd
dr-x------ 2 work work 0 2021-10-17 21:41:53 fdinfo
-r-------- 1 work work 0 2021-10-17 21:41:53 io
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 limits
dr-x------ 2 work work 0 2021-10-17 21:41:53 map_files
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 maps
-rw------- 1 work work 0 2021-10-17 21:41:53 mem
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 mounts
dr-xr-xr-x 12 work work 0 2021-10-17 21:41:53 net
dr-x--x--x 2 work work 0 2021-10-17 21:41:53 ns
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 oom_adj
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 oom_score
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 oom_score_adj
lrwxrwxrwx 1 work work 0 2021-10-17 21:41:53 root -> /
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 sched
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 schedstat
-rw-r--r-- 1 work work 0 2021-10-17 21:41:53 setgroups
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 smaps
-r-------- 1 work work 0 2021-10-17 21:41:53 stack
-r--r--r-- 1 work work 0 2021-10-17 21:41:41 stat
-r--r--r-- 1 work work 0 2021-10-17 21:41:41 status
-r-------- 1 work work 0 2021-10-17 21:41:53 syscall
dr-xr-xr-x 3 work work 0 2021-10-17 21:41:53 task
-r--r--r-- 1 work work 0 2021-10-17 21:41:53 timers

可见内容是相当的多,我们来看看这里面常见的项:

# cmdline保存了进程启动的命令行
$ cat /proc/397/cmdline|xargs -0
ncat -lk 8888 # cwd是个软链接,指向了进程的工作目录
$ readlink /proc/397/cwd
/home/work # environ保存了进程的环境变量
$ cat /proc/397/environ # exe是个软链接,指向了启动进程的命令程序
$ readlink /proc/397/exe
/usr/bin/ncat # status存储进程一些基础信息
$ cat /proc/397/status
Name: ncat
Umask: 0022
State: S (sleeping)
Tgid: 397
Ngid: 0
Pid: 397
PPid: 31607
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000 # /task目录保存进程的线程相关信息
cat /proc/397/task/ # fd目录里面保存着进程打开的文件描述符,可以用来查看进程打开了什么文件,打开了多少网络连接
$ ll /proc/397/fd
total 0
lrwx------ 1 work work 64 2021-10-17 21:47:23 0 -> /dev/pts/3
l-wx------ 1 work work 64 2021-10-17 21:47:23 1 -> /home/work/app.log
lrwx------ 1 work work 64 2021-10-17 21:47:23 2 -> /dev/pts/3
lrwx------ 1 work work 64 2021-10-17 21:47:23 3 -> 'socket:[49436]'
lrwx------ 1 work work 64 2021-10-17 21:47:23 4 -> 'socket:[49437]' # maps保存了进程的内存段映射信息,pmap命令取的就是这里面的数据
# 如果你是C/C++系开发者,可能会相对熟悉一些
$ cat /proc/397/maps | head
5606c2808000-5606c280d000 r--p 00000000 08:10 11419 /usr/bin/ncat
5606c280d000-5606c282f000 r-xp 00005000 08:10 11419 /usr/bin/ncat
5606c282f000-5606c283d000 r--p 00027000 08:10 11419 /usr/bin/ncat
5606c283e000-5606c283f000 r--p 00035000 08:10 11419 /usr/bin/ncat
5606c283f000-5606c2840000 rw-p 00036000 08:10 11419 /usr/bin/ncat
5606c2840000-5606c2841000 rw-p 00000000 00:00 0
5606c397e000-5606c399f000 rw-p 00000000 00:00 0 [heap]
7f0c7a5ce000-7f0c7a5d0000 rw-p 00000000 00:00 0
7f0c7a5d0000-7f0c7a5df000 r--p 00000000 08:10 44447 /usr/lib/x86_64-linux-gnu/libm-2.31.so
7f0c7a5df000-7f0c7a686000 r-xp 0000f000 08:10 44447 /usr/lib/x86_64-linux-gnu/libm-2.31.so # net目录保存着网络相关的信息,如下/net/tcp保存着进程的tcp连接信息
$ cat /proc/397/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:22B8 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 49437 1 0000000007f9a245 100 0 0 10 0 # sched保存着进程被调度的一些信息,如:
# se.nr_migrations线程迁移次数
# nr_voluntary_switches自愿上下文切换次数
# nr_involuntary_switches非自愿上下文切换次数
$ cat /proc/397/sched
ncat (397, #threads: 1)
-------------------------------------------------------------------
se.exec_start : 85694324.807968
se.vruntime : 333882.289243
se.sum_exec_runtime : 10.572689
se.nr_migrations : 0
nr_switches : 10
nr_voluntary_switches : 10
nr_involuntary_switches : 0
se.load.weight : 1048576
se.runnable_weight : 1048576
se.avg.load_sum : 42293
se.avg.runnable_load_sum : 42293
se.avg.util_sum : 26159838
se.avg.load_avg : 914
se.avg.runnable_load_avg : 914
se.avg.util_avg : 552
se.avg.last_update_time : 85694324807680
se.avg.util_est.ewma : 499
se.avg.util_est.enqueued : 553
policy : 0
prio : 120
clock-delta : 43

通过工作目录找进程
有时候,多个相同的程序部署在同一台机器上,比如Tomcat,但你只知道你们的Tomcat在/home/work/tomcat_order/目录,这时可以查询出各个tomcat进程的工作目录(cwd),然后辨别哪个是自己的Tomcat,如下:

# 查询各java进程的工作目录,注:tomcat是java实现的
# 可以看到867进程的工作目录是/home/work/tomcat_order/,那它就是我们要找的进程啰
$ pgrep java | xargs -i ls -l /proc/{}/cwd
lrwxrwxrwx 1 work work 0 2021-10-17 22:15:30 /proc/867/cwd -> /home/work/tomcat_order
lrwxrwxrwx 1 work work 0 2021-10-17 22:15:30 /proc/885/cwd -> /home/work/tomcat_goods
lrwxrwxrwx 1 work work 0 2021-10-17 22:15:42 /proc/906/cwd -> /home/work/tomcat_stock

找进程的日志文件
在排查问题时,经常需要查阅日志文件,如果你记不住相关进程的日志文件写到什么目录了,就可以通过/proc/$pid/fd/目录来查找,如下:

$ ll /proc/867/fd | grep .log$
l-wx------ 1 work work 64 2021-10-17 22:24:03 1 -> /home/work/app.log

netstat查看网络连接#

netstat是用来查看网络连接信息的工具命令,具体来说,像在编程语言中可以通过创建socket来建立网络连接,而netstat就是用来查看这些socket信息的,如下:

# 查看所有的socket,-n代表不解析ip为主机名,-a表示all所有,-t代表tcp
$ netstat -nat # 显示各状态socket数量,TIME_WAIT与CLOSE_WAIT数量太多,一般都不是好事情
$ netstat -nat | awk '/tcp/{print $6}'|sort|uniq -c
21 ESTABLISHED
3 TIME_WAIT
3 CLOSE_WAIT
2 LISTEN # 查看LISTEN状态的socket,-l代表只显示LISTEN状态的
$ netstat -nlt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN
tcp6 0 0 :::8888 :::* LISTEN # 查看进程867的socket数量,-p显示出创建网络连接的进程号
$ netstat -natp|grep -w 867 -c
2 # 找到监听在8888端口的进程
$ netstat -nltp|grep -w 8888
tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN 867/ncat
tcp6 0 0 :::8888 :::* LISTEN 867/ncat

lsof查看打开文件#

在Linux的设计哲学中,"一切皆文件",像进程(/proc/$pid)、网络连接(/proc/net/tcp)、主机设备(/dev)等,Linux也都把它虚拟成了文件,方便程序或shell读取,就像上面的ps命令,如果你愿意,通过读取/proc目录的数据,可以非常容易地实现自己的ps命令!

而lsof(list open files)命令,就是用来查看系统或进程打开的文件的,所以这个命令非常的强大,它几乎是观测软件资源最好用的工具了,如下:

# 查看系统打开的所有文件(包括网络连接等)
$ lsof # 查看进程867打开的文件(包括网络连接等),-p指定具体进程号
$ lsof -p 867 # 类似上面介绍的,查找进程的日志文件
$ lsof -p 867 | grep .log$ # 类似上面介绍的,查看java进程的工作目录, -c java表示过滤出java进程的文件,-d cwd表示过滤出工作目录
# 而-a表示-c与-d是AND关系(默认OR),即java进程的cwd文件,就是工作目录
$ lsof -a -c java -d cwd
ncat 867 work 1w REG 8,16 0 171403 /home/work/app.log # 显示进程867的tcp连接,-n不解析ip为主机名,-P不解析端口为服务名,-i TCP显示TCP连接
$ lsof -a -nP -i TCP -p 867
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ncat 867 work 3u IPv6 48737 0t0 TCP *:8888 (LISTEN)
ncat 867 work 4u IPv4 48738 0t0 TCP *:8888 (LISTEN) # 显示8888号端口的连接
$ lsof -nP -i :8888
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ncat 867 work 3u IPv6 48737 0t0 TCP *:8888 (LISTEN)
ncat 867 work 4u IPv4 48738 0t0 TCP *:8888 (LISTEN) # 显示与172.16.12.5主机的连接
$ lsof -nP -i @172.16.12.5 # 通过指定目录或文件找进程
$ lsof /home/work/app.log
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ncat 867 work 1w REG 8,16 0 171403 /home/work/app.log

有时候,系统磁盘空间不足了,我们想删掉一些大的日志文件来释放磁盘空间,却发现删除后,磁盘剩余空间没有变多,这是因为有进程引用了这个文件,可以如下确认:

# 找出已删除但被进程引用的文件
$ lsof | grep deleted
ncat 867 work 1w REG 8,16 0 171403 /home/work/app.log (deleted)

这时我们只需要重启867这个进程,即可真正释放空间。

注:可以这么理解,删除文件只是去掉了文件系统对这个文件的引用,而如果进程之前还打开了这个文件,那进程中保有的文件描述符也是引用了这个文件的,此时文件还不能回收,因为回收可能会导致进程出错,然而重启进程后,对文件的所有引用就都没有了,文件占用的空间才能被真正回收。

实践#

1、陌生环境找服务日志#

当我们刚开始接手一些系统时,对系统的部署情况不太了解,比如订单系统的数据库地址是test.mycat.order.proxy:8566,它是个mycat,部署在test.mycat.order.proxy机器上,但运维在这台机器上还部署了好几个其它系统的mycat,那怎么找到自己的mycat进程,并找到其gc日志呢?

  1. 登录test.mycat.order.proxy,根据8566端口找进程
$ netstat -nltp|grep -w 8566
tcp 0 0 0.0.0.0:8566 0.0.0.0:* LISTEN 467313/haproxy

可见8566并不是mycat进程,而是一个网络代理haproxy,对于网络代理进程,它连出最多的端口,一般就是代理后面的服务提供的,所以我们需要再查一下haproxy创建了哪些连接。

  1. 查找haproxy创建了哪些连接
# 注:467313是haproxy的进程号
$ netstat -natp|grep 467313
tcp 0 0 0.0.0.0:8566 0.0.0.0:* LISTEN 467313/haproxy
tcp 0 0 10.12.231.1:8566 10.39.12.32:42282 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:8566 10.39.12.32:36638 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:21103 10.12.231.1:8466 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:31417 10.12.231.1:8466 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:48432 10.12.231.1:8466 ESTABLISHED 467313/haproxy
tcp 0 0 10.12.231.1:59047 10.12.231.1:8466 ESTABLISHED 467313/haproxy

可见,haproxy进程连出最多的是8466端口。

  1. 再根据8466端口找进程
$ netstat -nltp|grep -w 8466
tcp 0 0 0.0.0.0:8466 0.0.0.0:* LISTEN 956758/java

找到了一个java进程,mycat就是java实现的,那这个估计就是我们的mycat进程了,如下确认一下:

  1. 查看进程详情
$ ps -fp 956758 | cat
UID PID PPID C STIME TTY TIME CMD
work 956758 956756 11 Oct15 ? 09:15:36 java -DMYCAT_HOME=. -server -XX:MaxPermSize=128M -XX:-UseGCOverheadLimit -XX:+AggressiveOpts -XX:MaxDirectMemorySize=4G -XX:+HeapDumpOnOutOfMemoryError ... $ ll /proc/956758/cwd
lrwxrwxrwx 1 work work 0 Oct 15 16:22 /proc/956758/cwd -> /home/work/order/mycat

可见,它就是个mycat,且其工作目录在/home/work/order/mycat

  1. 查找其gc日志
$ ll /proc/956758/fd | grep .log$
l-wx------ 1 work work 64 Oct 16 14:12 3 -> /home/work/order/mycat/logs/gc-2021-10-15_15-27-40.log
l-wx------ 1 work work 64 Oct 16 14:12 57 -> /home/work/order/mycat/logs/sql_time.log
l-wx------ 1 work work 64 Oct 16 14:12 58 -> /home/work/order/mycat/logs/mycat_auth.log
l-wx------ 1 work work 64 Oct 16 14:12 59 -> /home/work/order/mycat/logs/error_msg.log
l-wx------ 1 work work 64 Oct 16 14:12 60 -> /home/work/order/mycat/logs/mycat_prepare.log
l-wx------ 1 work work 64 Oct 16 14:12 61 -> /home/work/order/mycat/logs/sql_error_msg.log

这样,我们就在自己本不熟悉的机器环境里,找到了自己服务的gc日志。

2、文件描述符泄露#

系统的文件描述符资源是有限的,用完了必须归还,不然就会发生泄露,对应在Java中的场景如下:

a. 通过fis=new FileInputStream("xxx")打开文件,读取完文件后,必须调用fis.close()关闭,不然FD(file descriptor)创建越来越多,导致oom。
b. jdbc中通过conn=DriverManager.getConnection()获取连接,操作完数据库后,必须调用conn.close()关闭,不然就会socket创建越来越多(socket也是一种文件,也有FD),导致oom。

要想确认java服务中,是否存在那种忘记调用close的地方,只需要不断监控进程的FD数量,如果它一直都在增长,基本就是发生了泄露,如下:

$ while true; do pgrep java | xargs -i ls -l /proc/{}/fd | wc -l; sleep 10; done | tee fd_num.log
12303
12292
12290

往期内容#

Linux命令拾遗-入门篇
原来awk真是神器啊
Linux文本命令技巧(上)
Linux文本命令技巧(下)
字符编码解惑

作者:打码日记

出处:https://www.cnblogs.com/codelogs/p/16060443.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

 
 
 

[转帖] Linux命令拾遗-软件资源观测的更多相关文章

  1. [转帖]Linux命令中特殊符号

    Linux命令中特殊符号 转自:http://blog.chinaunix.net/uid-16946891-id-5088144.html   在shell中常用的特殊符号罗列如下:# ; ;; . ...

  2. [转帖]Linux命令pmap

    Linux命令pmap https://www.cnblogs.com/lnlvinso/p/5272771.html jmap可以查看Java程序的堆内存使用情况,pmap可以查看Linux上运行的 ...

  3. [转帖]linux命令dd

    linux命令dd   dd 是diskdump 的含义 之前学习过 总是记不住 用的还是少. http://embeddedlinux.org.cn/emb-linux/entry-level/20 ...

  4. linux 命令拾遗

    man ascii 这个命令会打印出八进制.十六进制和十进制的ASCII码表. xxd xxd可以生成所给与文件的十六进制拷贝,也可以将编辑好的十六进制拷贝还原成二进制格式.它也可以将十六进制拷贝输出 ...

  5. [转帖]50个必知的Linux命令技巧,你都掌握了吗?

    50个必知的Linux命令技巧,你都掌握了吗? https://blog.51cto.com/lizhenliang/2131141 https://blog.51cto.com/lizhenlian ...

  6. 【转帖】Linux命令行操作json神器jq

    Linux命令行操作json神器jq https://www.cnblogs.com/chenqionghe/p/11736942.html jq类似一个awk或grep一样的神器,可以方便地在命令行 ...

  7. [转帖]linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习)

    linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习) https://www.cnblogs.com/caozy/p/9261224.html 总结的挺好的 ...

  8. Linux 命令快捷键

    Linux 命令快捷键 tab 自动补齐(有不知道的吗)Ctrl+u 删除(剪切)此处至开始所有内容 Ctrl+k 删除从光标所在位置到行末 快速命令行 – 快捷方式• history 搜索历史执行过 ...

  9. Linux命令自己总结

    对于每一个Linux学习者来说,了解Linux文件系统的目录结构,是学好Linux的至关重要的一步.,深入了解linux文件目录结构的标准和每个目录的详细功能,对于我们用好linux系统只管重要,下面 ...

  10. 20个Linux命令及Linux终端的趣事

    20个Linux命令及Linux终端的趣事 . 命令:sl (蒸汽机车) 你可能了解 ‘ls’ 命令,并经常使用它来查看文件夹的内容.但是,有些时候你可能会拼写成 ‘sl’ ,这时我们应该如何获得一些 ...

随机推荐

  1. 解锁华为云AI如何助力无人车飞驰“新姿势”,大赛冠军有话说

    摘要:在2020年第二届华为云人工智能大赛•无人车挑战杯赛道中,"华中科技大学无人车一队"借助华为云一站式AI开发与管理平台ModelArts及HiLens端云协同AI开发应用平台 ...

  2. 基于ModelArts进行流感患者密接排查

    摘要:针对疫情期间存在的排查实时性差.排查效率低.无法追踪密接者等问题,可以使用基于YOLOv4的行人检测.行人距离估计.多目标跟踪的方案进行解决. 本文分享自华为云社区<基于ModelArts ...

  3. 基于OpenHarmony L2设备,如何用IoTDeviceSDKTiny对接华为云

    摘要:本文主要讲解如何基于L2设备对接华为云IoTDA,以DAYU200开发板,采用IoTDeviceSDKTiny对接华为云IoTDA,当然这里也可以采用其他OpenHarmony的富设备. 本文分 ...

  4. 适合新手的12个Mybatis-Plus常用注解

    摘要:MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发.提高效率而生. 本文分享自华为云社区<那些年,我们一起学过 ...

  5. 揭秘华为云GaussDB(for Influx):最佳实践之数据建模

    摘要:本期将从GaussDB(for Influx)数据模型谈起,分享GaussDB(for Influx)数据建模的最佳方法,避免一些使用过程中的常见问题. 本文分享自华为云社区<华为云Gau ...

  6. iOS移动应用安全加固:保护您的App免受恶意攻击的重要步骤

    ​ 目录 iOS移动应用安全加固:保护您的App免受恶意攻击的重要步骤 摘要 引言 一.APP加固的概念 二.APP加固方案的比较 三.保护iOS应用的安全 四.总结 参考资料 摘要 本文介绍了移动应 ...

  7. 1个案例读懂——游戏产品如何用 A/B 测试做增长

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 随着国内游戏用户数量趋于饱和,中国游戏产业也从高速成长期逐渐转型,市场成熟度提升,竞争趋于精细化. 随着游戏出海以 ...

  8. PPT 光效果

    点状.线状.面状.光影 "光" = PPT高大上的秘密

  9. lab3 page tables

    1.Speed up system calls (easy) 要求:有些操作系统(例如 Linux)通过在用户空间和内核之间的只读区域共享数据来加速某些系统调用.这样可以消除在执行这些系统调用时进行内 ...

  10. c#-微软2

    练习-编写第一个代码: 在第一次练习中你将使用c#将神圣的程序员用语打印到控制台的标准输出 编写第一行代码: 在软件开发者中,有这么一个传统,那就是将"Hello World!"这 ...