学习随笔

函数式编程思维

函数式编程关心数据的映射,命令式编程关心解决问题的步骤

这里的映射就是数学上「函数」的概念——一种东西和另一种东西之间的对应关系。

用两个例子说明 命令式编程 与 函数式编程的差别

命令时编程

假如,现在你来到 google 面试,面试官让你把二叉树镜像反转一下(大雾

几乎不假思索的,就可以写出这样的 Python 代码:

1
2
3
4
5
def invertTree(root):
if root is None:
return None
root.left, root.right = invertTree(root.right), invertTree(root.left)
return root

它的含义是:首先判断节点是否为空;然后翻转左树;然后翻转右树;最后左右互换。

这就是命令式编程——你要做什么事情,你得把达到目的的步骤详细的描述出来,然后交给机器去运行。

这也正是命令式编程的理论模型——图灵机的特点。一条写满数据的纸带,一条根据纸带内容运动的机器,机器每动一步都需要纸带上写着如何达到。

函数式编程

所谓“翻转二叉树”,可以看做是要得到一颗和原来二叉树对称的新二叉树。这颗新二叉树的特点是每一个节点都递归地和原树相反。

1
2
3
4
5
def invert(node):
if node is None:
return None
else
return Tree(node.value, invert(node.right), invert(node.left))

这段代码体现的思维,就是旧树到新树的映射——对一颗二叉树而言,它的镜像树就是左右节点递归镜像的树。

这段代码最终达到的目的同样是翻转二叉树,但是它得到结果的方式和 命令式编程有着本质的差别:通过描述一个 旧树->新树 的映射,而不是描述「从旧树得到新树的步骤」来达到目的。

函数式编程的好处

  1. 函数式风格的代码可以写得很精简
  2. 函数式的代码是“对映射的描述”,任何能在计算机中事物的任何对应关系都可以描述——比如函数和函数之间的映射(比如 functor);比如外部操作到 GUI 之间的映射(就是现在前端热炒的所谓 FRP)。它的抽象程度很高,这就意味着函数式的代码可以更方便的复用

操作系统内存管理

源代码变为运行程序的几个步骤

  1. 编译
  2. 链接/前绑定 后绑定
  3. 装入内存

程序装入

  1. 绝对装入:编译后产生绝对地址的目标代码,只适用于单道程序环境

  2. 静态重定位:编译后汇编代码中的地址都是相对于程序起始地址的,地址变换在装入时一次性完成,因此称为静态重定位

  3. 动态重定位:不仅在编译后汇编代码中的地址是相对地址,在装入后汇编代码中的地址仍然是相对地址,只有在运行时,借助重定位寄存器,才能得到存储空间中真实地址。

    特点:

    1. 程序可以不连续
    2. 动态分配内存

内存分配管理

连续分配

单一连续分配

  1. 内存中永远只有一道程序
  2. 优点:简单,无外部碎片
  3. 缺点:单用户,单任务,有内部碎片,Mem利用率极低

固定分区分配

  1. 将用户内存空间分为若干个大小固定的区域,每个区域只装入一个作业,会具有内部碎片
    1. 分为大小相等的区域:缺乏灵活性,程序的大小一般差别较大,不适合
    2. 分为大小不等的区域:能够适应不同程序的大小

动态分区分配/可变分区分配

  1. 概念:在程序装入时,根据程序的大小,动态分配内存
  2. 分配算法:
    1. 首次适应:用第一个找到的满足大小的块分配
    2. 最好适应:用分区大小最小且满足大小的块分配
    3. 最坏适应:用分区大小最大且满足大小的块分配
    4. 邻近适应:改进的首次适应算法,从上一次分配的位置开始查找,用第一个找到的满足大小的块分配
    5. 算法比较:首次适应>邻近适应>最好适应>最坏适应

非连续分配方式

分页内存管理

  1. 概念:
    1. 进程中的块分为内存中的块成为 页框外存中的块 成为 ,本质上一个东西,在不同时刻,以不同身份呈现,当从静态程序角度来看,为页,若未装入内存则为块,若装入内存,则为页帧/页框
    2. 地址结构为 页号+页内偏移量,因为页大小相同,可以通过 地址结构/页大小 得到页号
    3. 具有页表,页表段的结构是 页号+页帧号,将逻辑上的页号,映射到内存中实际的页帧中
    4. 根据局部性原理,设置块表(TLB 联想寄存器)存放经常访问的页表项,加速地址变换

二级分页内存管理

  1. 概念:二级页表,将页表再进行一次抽象和映射
  2. 地址结构: 一级页表号+二级页表号+页内偏移
  3. 第一级页表 只有一个

分段内存管理

  1. 概念:段内要求连续,段间不要求连续,段的大小不一致
  2. 地址结构:段号+段内偏移量
  3. 段表项:段号+段长+内存中实际起始地址

段页式内存管理

  1. 结合段式和页式,第一层分段,在段内分页
  2. 地址结构:段号+页号+页内偏移

局部性原理

时间局部性

  1. 刚被访问过的数据或者被执行过的代码,有较大的可能性再次被访问和执行
  2. 原因:程序中存在比较多的循环

空间局部性

  1. 当前被访问的存储单元,刚被执行的代码 附近的存储单元或代码 有较大的可能性被访问和执行
  2. 原因:1. 程序的顺序存放和执行 2.数据的顺序存放(至少在逻辑上常以list等出现,再物理上也不是完全分散)

每一Linux命令

Junit4

作用:

自动的创建单元测试类和单元测试函数,但是单元测试函数内的逻辑实现显然仍需要人来完成(assertEquals 方法)

JUnit使用的最佳实践

①测试方法上必须使用@Test进行修饰
②测试方法必须使用public void 进行修饰,不能带任何的参数
③新建一个源代码目录来存放我们的测试代码,即将测试代码和项目业务代码分开
④测试类所在的包名应该和被测试类所在的包名保持一致
⑤测试单元中的每个方法必须可以独立测试,测试方法间不能有任何的依赖
测试类使用Test作为类名的后缀(不是必须)

测试方法使用test作为方法名的前缀(不是必须)

注解:

@Test:把一个方法标记为测试方法

@Before:每一个测试方法执行前自动调用一次

@After:每一个测试方法执行完自动调用一次

@BeforeClass:所有测试方法执行前执行一次,在测试类还没有实例化就已经被加载,所以用static修饰

@AfterClass:所有测试方法执行完执行一次,在测试类还没有实例化就已经被加载,所以用static修饰

@BeforeClass,@AfterClass:通常用来初始化和关闭资源

@Ignore:暂不执行该测试方法

注意:

单元测试类会在每个单元测试函数执行前重新new一个新对象,确保单元测试函数互相不影响(也就是类的构造函数会执行多次)

@Test的属性

  • excepted,和fail方法搭配可以用以测试异常
1
2
3
4
5
@Test(expected = Exception.class)
public void testFactorialException() throws Exception {
new Math().factorial(-1);
fail("factorial参数为负数没有抛出异常");
}
  • timeout,用以测试性能
1
2
3
4
5
6
7
8
9
10
11
@Test(timeout = 2000)
public void testSort() throws Exception {
int[] arr = new int[50000]; //数组长度为50000
int arrLength = arr.length;
//随机生成数组元素
Random r = new Random();
for (int i = 0; i < arrLength; i++) {
arr[i] = r.nextInt(arrLength);
}
new Math().sort(arr);
}

ArrayList

扩容

删除元素

fail-fast

modCount 用来记录 ArrayList 结构发生变化的次数;包括:增加元素,删除元素,扩容。(修改某个位置的元素没有改变结构)

在进行serialization或者iterator迭代等操作时,需要比较操作前后 modCount 是否改变,如果改变了需要抛出 ConcurrentModificationException。

1
2
3
4
5
6
7
8
9
10
11
List<Integer> list = new ArrayList< (Arrays.asList(0,1,2,3,4,5));
Iterator<Integer> it = list.iterator();
while (it.hasNext()){
int data = it.next();
System.out.println(data);
if (data == 3){
it.remove(); // 不会产生问题
// list.remove(3) // 会产生问题
}
}
System.out.println(list);

上述代码一个产生ConcurrentModificationException 另一个不会的原因在于,通过iterator.remove() 除了删除元素之外(调用 AarrayList的remove方法),还修改了expectedModCount 因此不会产生问题

见源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
// 调用 AarrayList的remove方法
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
// 修改了expectedModCount
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new
ConcurrentModificationException();
}
}

序列化

  1. 保存元素的数组 elementData 使用 transient 修饰,该关键字声明数组默认不会被序列化。

  2. ArrayList 利用实现 writeObject() 和 readObject() 来控制只序列化数组中有元素填充那部分内容

    详见cs_notes 源码部分

#Linux

April 28: pwd

pwd:显示当前得目录,有两个参数 pwd - [PL], 默认是pwd -L

场景:root下有一个软连接 html 连接至 /usr/share/nginx/html/portal

pwd -P 显示 physical 实际目录

在root/html下 使用 pwd -P 返回 /usr/share/nginx/html/portal

pwd -L 显示 link 软连接目录

在root/html下 使用 pwd -L 返回 root/html

April 28: tail

作用:将文件最后10行内容打印至标准输出 Print the last 10 lines of each FILE to standard output.

使用方式:Usage: tail [OPTION]… [FILE]…

例子:tail -n 5 log2014.log

参数:

-f/F, –follow[={name|descriptor}] 文件更新时将最新内容输出,常用作监视log文件
output appended data as the file grows;
an absent option argument means ‘descriptor’

–pid=PID 与-f/F 合用 当进程结束时终止命令 with -f, terminate after process ID, PID dies

-s, –sleep-interval=N 与-f合用,表示在每次反复的间隔休眠S秒 with -f, sleep for approximately N seconds

-n, –lines=K 指定最后输出的行数 c count output the last K lines, instead of the last 10;

-c, –bytes=K 指定最后输出的字节数 c count output the last K bytes; or use -c +K to output

-q, –quiet, –silent never output headers giving file names
–retry keep trying to open a file if it is inaccessible

-v, –verbose always output headers giving file names

–help display this help and exit
–version output version information and exit

April 29: mkdir

创建目录

mkdir [选项] 目录

参数

-m, –mode=模式,设定权限<模式> (类似 chmod),而不是 rwxrwxrwx 减 umask (777)

-p, –parents 可以是一个路径名称。此时若路径中的某些目录尚不存在,加上此选项后,系统将自动建立好那些尚不存在的目录,即一次可以建立多个目录;

-v, –verbose 每次创建新目录都显示信息

例子:

mkdir -p test2/test22 如果目录test2不存在先创建test2,在创建test22

mkdir -m 777 test3 创建权限为777的目录

mkdir -vp scf/{lib/,bin/,doc/{info,product},logs/{info,product},service/deploy/{info,product}} 一个命令创建项目的目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[lbc@wds mkdir]$ mkdir -vp scf/{lib/,bin/,doc/{info,product},logs/{info,product},service/deploy/{info,product}}
mkdir: created directory ‘scf’
mkdir: created directory ‘scf/lib/’
mkdir: created directory ‘scf/bin/’
mkdir: created directory ‘scf/doc’
mkdir: created directory ‘scf/doc/info’
mkdir: created directory ‘scf/doc/product’
mkdir: created directory ‘scf/logs’
mkdir: created directory ‘scf/logs/info’
mkdir: created directory ‘scf/logs/product’
mkdir: created directory ‘scf/service’
mkdir: created directory ‘scf/service/deploy’
mkdir: created directory ‘scf/service/deploy/info’
mkdir: created directory ‘scf/service/deploy/product’

April 30: rm

rm是删除命令,有几个参数不是很常用

​ -i, –interactive 进行交互式删除

​ -d, –dir 删除空目录

​ -f, –force 忽略不存在的文件,从不给出提示。

​ -r, -R, –recursive 指示rm将参数中列出的全部目录和子目录均递归地删除。

​ -v, –verbose 详细显示进行的步骤

April 30: rmdir

该命令的功能是删除空目录,一个目录被删除之前必须是空的, 若是非空目录,则操作失败,rm -d 也能删除空目录,但是该命令具有更多功能.

参数:

​ -p, –parent 如果删除当前空目录后,其父目录也为空,则将父目录也删除

​ -v,–verbose

May 7: cat

cat命令的用途是连接文件或标准输入并打印。这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用

cat主要有三大功能:

1.一次显示整个文件:cat filename

2.从键盘创建一个文件:cat > filename 只能创建新文件,不能编辑已有文件.

3.将几个文件合并为一个文件:cat file1 file2 > file

命令参数:

-A, –show-all 等价于 -vET

-b, –number-nonblank 对非空输出行编号

-e 等价于 -vE

-E, –show-ends 在每行结束处显示 $

-n, –number 对输出的所有行编号,由1开始对所有输出的行数编号

-s, –squeeze-blank 有连续两行以上的空白行,就代换为一行的空白行

-t 与 -vT 等价

-T, –show-tabs 将跳格字符显示为 ^I

-u (被忽略)

-v, –show-nonprinting 使用 ^ 和 M- 引用,除了 LFD 和 TAB 之外

May 8: netstat

https://www.cnblogs.com/peida/archive/2013/03/08/2949194.html

查找进程的端口

netstat -nap | grep [进程名/进程PID]

查找占用某个端口的进程

netstat -nap | grep [端口]

解析

netstat -n(numeric, 显示IP地址而非域名)a(all)p(program,显示进程信息)

1557575974305

May 9: nl

https://www.cnblogs.com/peida/archive/2012/11/01/2749048.html

nl命令在linux系统中用来计算文件中行号。nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等等的功能。

1.命令格式:

nl [选项]… [文件]…

2.命令参数:

-b :指定行号指定的方式,主要有两种:

-b a :表示不论是否为空行,也同样列出行号(类似 cat -n);

-b t :如果有空行,空的那一行不要列出行号(默认值);

-n :列出行号表示的方法,主要有三种:

-n ln :行号在萤幕的最左方显示;

-n rn :行号在自己栏位的最右方显示,且不加 0 ;

-n rz :行号在自己栏位的最右方显示,且加 0 ;

-w :行号栏位的占用的位数。

-p 在逻辑定界符处不重新开始计算

May 10: more & less

less 工具也是对文件或其它输出进行分页显示的工具,应该说是linux正统查看文件内容的工具,功能极其强大。less 的用法比起 more 更加的有弹性。在 more 的时候,我们并没有办法向前面翻, 只能往后面看,但若使用了 less 时,就可以使用 [pageup] [pagedown] 等按键的功能来往前往后翻看文件,更容易用来查看一个文件的内容!除此之外,在 less不止可以向下搜,也可以向上搜

https://www.cnblogs.com/peida/archive/2012/11/02/2750588.html

https://www.cnblogs.com/peida/archive/2012/11/05/2754477.html

May 11: head & tail

head 与 tail 就像它的名字一样的浅显易懂,它是用来显示开头或结尾某个数量的文字区块,head 用来显示档案的开头至标准输出中,而 tail 想当然尔就是看档案的结尾

tail -f 一般用于查看日志内容

1.命令格式:

head [参数]… [文件]…

tail[必要参数] [选择参数] [文件]

3.命令参数:

-q 隐藏文件名

-v 显示文件名

-c<字节> 显示字节数

-n<行数> 显示的行数

———tail专属参数———————-

-f (follow) 跟随读取,文件更新时读取更新内容

-s, –sleep-interval=S 与-f合用,表示在每次反复的间隔休眠S秒

May 12: which, whereis, locate, find

which:常用于查找可直接执行的命令。只能查找可执行文件,该命令基本只在$PATH路径中搜索,查找范围最小,查找速度快。默认只返回第一个匹配的文件路径,通过选项 -a 可以返回所有匹配结果。

whereis不只可以查找命令,其他文件类型都可以man中说只能查命令、源文件和man文件,实际测试可以查大多数文件)。在$PATH路径基础上增加了一些系统目录的查找,查找范围比which稍大,查找速度快可以通过 -b 选项,限定只搜索二进制文件

locate:超快速查找任意文件。它会从linux内置的索引数据库查找文件的路径,索引速度超快;会遗漏某些新的还未加入索引数据库的文件,也会搜出一些已被删除但是仍存在于索引数据库中的文件,可以通过执行updatedb命令来强制更新一次索引,这样确保不会遗漏文件。该命令通常会返回大量匹配项,可以使用 -r 选项通过正则表达式来精确匹配。

find直接搜索整个文件目录,默认直接从根目录开始搜索,建议在以上命令都无法解决问题时才用它,功能最强大但速度超慢。除非你指定一个很小的搜索范围。通过 -name 选项指定要查找的文件名,支持通配符

https://www.cnblogs.com/peida/archive/2012/11/13/2767374.html

https://www.cnblogs.com/peida/archive/2012/11/16/2773289.html

May 14: crontab定时任务

https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/crontab.html

Usage:

crontab [options] file
crontab [options]
crontab -n [hostname]

Options:

-u define user
-e edit user’s crontab
-l list user’s crontab
-r delete user’s crontab
-i prompt before deleting
-n set host in cluster to run users’ crontabs
-c get host in cluster to run users’ crontabs
-s selinux context
-x enable debugging

使用方式一:修改当前用户的crontab 文件

  1. 编辑crontab 文件

    crontab -e

  2. 编进内容

    crontab的文件格式: 分 时 日 月 星期 要运行的命令

    • 第1列分钟0~59
    • 第2列小时0~23(0表示子夜)
    • 第3列日1~31
    • 第4列月1~12
    • 第5列星期0~7(0和7表示星期天)
    • 第6列要运行的命令
    1
    2
    #注释行  每小时的第3和第15分钟执行
    3,15 * * * * myCommand3

使用方式二:新建crontab 文件

  1. 新建crontab文件
    1. vim [cron 文件名]
  2. vim 编辑内容
  3. crontab [cron 文件名] 使其生效

使用注意事项

注意环境变量问题

有时我们创建了一个crontab,但是这个任务却无法自动执行,而手动执行这个任务却没有问题,这种情况一般是由于在crontab文件中没有配置环境变量引起的。

在crontab文件中定义多个调度任务时,需要特别注环境变量的设置,因为我们手动执行某个任务时,是在当前shell环境下进行的,程序当然能找到环境变量,而系统自动执行任务调度时,是不会加载任何环境变量的,因此,就需要在crontab文件中指定任务运行所需的所有环境变量,这样,系统执行任务调度时就没有问题了。

不要假定cron知道所需要的特殊环境,它其实并不知道。所以你要保证在shelll脚本中提供所有必要的路径和环境变量,除了一些自动设置的全局变量。所以注意如下3点:

  1. 脚本中涉及文件路径时写全局路径;

  2. 脚本执行要用到java或其他环境变量时,通过source命令引入环境变量,如:

    1
    2
    3
    4
    5
    cat start_cbp.sh
    !/bin/sh
    source /etc/profile
    export RUN_CONF=/home/d139/conf/platform/cbp/cbp_jboss.conf
    /usr/local/jboss-4.0.5/bin/run.sh -c mev &
  3. 当手动执行脚本OK,但是crontab死活不执行时,很可能是环境变量惹的祸,可尝试在crontab中直接引入环境变量解决问题。如:

    1
    0 * * * * . /etc/profile;/bin/sh /var/www/java/audit_no_count/bin/restart_audit.sh

May 15: source

source命令作用

在当前bash环境下读取并执行FileName中的命令

source命令用法

source FileName

source filename , bash filename , sh fileName及./filename执行脚本的区别

  1. ./filename: 当shell脚本具有可执行权限时,用sh filename与./filename执行脚本是没有区别得。./filename是因为当前目录没有在PATH中,所有”.”是用来表示当前目录的。

  2. bash filename: 重新建立一个子shell在其中执行脚本里面的语句,该子shell继承父shell的环境变量,但子shell新建的、改变的变量不会被带回父shell

  3. source filename:这个命令其实只是简单地读取脚本里面的语句依次在当前shell里面执行,没有建立新的子shell。那么脚本里面所有新建、改变变量的语句都会保存在当前shell里面

  4. sh(或Shell命令语言)是由POSIX standard描述的编程语言。它有许多实现(bash, ksh88,dash,…)。;因为sh是一个规范,而不是一个实现/ bin / sh是一个符号链接 (或硬链接)到大多数POSIX系统上的实际实现bash开始作为一个sh兼容的实现(虽然它早于POSIX标准几年),但随着时间的推移,它已经获得了许多扩展。许多这些扩展可能会改变有效的POSIX shell脚本的行为,所以bash本身不是一个有效的POSIX shell。相反,它是POSIX shell语言的方言

  5. 1
    0 * * * * . /etc/profile;/bin/sh /var/www/java/audit_no_count/bin/restart_audit.sh

May 16: xargs

详见博客 https://www.cnblogs.com/wangqiguo/p/6464234.html

  1. 作用: 将上一条命令的输出(保存在标准输出中;通过管道获取) 作为 下一条命令的 命令行参数

  2. linux 命令往往能够从 1. 命令行参数接受输入(类似于 main中的args) 2. 从标准输入中接受输入(类似于 scanf)

  3. 管道命令只是将 上一条命令作为 下一条命令的标准输入 / xargs 将标准输入转化为 命令行参数

    1
    ps -ef | grep 'ddd' | xargs kill

May 17: Linux 目录结构

May 18: Linux文件类型与扩展名

1. 文件类型

Linux文件类型常见的有:普通文件、目录文件、字符设备文件和块设备文件、符号链接文件等, 通过 ls -l 可以查看文件的类型

  1. 普通文件

    ls -l 会出现-rwxrwxrwx 其中 - 表示普通文件 rwxrwxrwx 表示文件的权限

  2. 目录文件

    drwxr-xr-x d 表示目录文件

  3. 字符设备或块设备文件

    crw-rw-rw- c表示字符设备文件

  4. 数据接口文件(sockets)

    第一个属性为 [ s ]

  5. 符号链接文件

    第一个属性为 [ l ]

  6. 数据输送文件(FIFO,pipe)

    第一个属性为[p]

2. Linux文件扩展名,文件类型

基本上,Linux的文件是没有所谓的扩展名(文件类型),一个Linux文件能不能被执行,与他的第一栏的十个属性有关, 与扩展名(文件类型)根本一点关系也没有

文件拓展名,文件类型只是 文件具体类型的参考

May 19: linux文件属性详解

Linux 文件或目录的属性主要包括:文件或目录的节点、种类、权限模式、链接数量、所归属的用户和用户组、最近访问或修改的时间等内容。具体情况如下:

命令:

-lih```
1
2

**输出:**

[root@localhost test]# ls -lih
总计 316K
2095120 lrwxrwxrwx 1 root root 11 11-22 06:58 linklog.log -> log2012.log
2095112 -rw-r–r– 1 root root 296K 11-13 06:03 log2012.log
2095110 -rw-r–r– 1 root root 61 11-13 06:03 log2013.log
2095107 -rw-r–r– 1 root root 0 11-13 06:03 log2014.log
2095117 -rw-r–r– 1 root root 0 11-13 06:06 log2015.log
2095118 -rw-r–r– 1 root root 0 11-16 14:41 log2016.log
2095119 -rw-r–r– 1 root root 0 11-16 14:43 log2017.log
2095113 drwxr-xr-x 6 root root 4.0K 10-27 01:58 scf
2095109 drwxrwxr-x 2 root root 4.0K 11-13 06:08 test3
2095131 drwxrwxr-x 2 root root 4.0K 11-13 05:50 test4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

**说明:**

第一列:inode

第二列:文件种类和权限 (文件类型/文件属主读写执行权限/同一用户组用户权限/其他用户权限)

第三列: 硬链接个数;

第四列: 属主;

第五列:所归属的组;

第六列:文件或目录的大小;

第七列和第八列:最后访问或修改时间;

第九列:文件名或目录名

**关于inode:**

1. **inode**:一个文件占用一个 inode,记录文件的属性,同时记录此文件的内容所在的 block 编号;
2. **block**:记录文件的内容,文件太大时,会占用多个 block

## May 20: [chmod](https://www.cnblogs.com/peida/archive/2012/11/29/2794010.html) (change mode)

## May 21: [chgrp](https://www.cnblogs.com/peida/archive/2012/12/03/2799003.html) (change group)改变文件或者目录所属的group

## May 22: [chown](https://www.cnblogs.com/peida/archive/2012/12/04/2800684.html) (change owner)改变文件或者目录的拥有者

## May 23: [chown](https://www.cnblogs.com/peida/archive/2012/12/04/2800684.html) (change owner)改变文件或者目录的拥有者

## May 24: [/etc/group文件详解](https://www.cnblogs.com/peida/archive/2012/12/05/2802419.html) 存放组信息的文件

## May 25: [/etc/passwd 文件详解](https://www.ibm.com/support/knowledgecenter/zh/ssw_aix_71/com.ibm.aix.security/passwords_etc_passwd_file.htm) 存放用户信息的文件

## May 26: /etc/shadow 文件详解 存放加密后的用户密码的文件

[参考1](https://blog.csdn.net/ouyang_peng/article/details/8732644)

[参考2](https://blog.csdn.net/snlying/article/details/6130468)

## May 27: [df ](https://www.cnblogs.com/peida/archive/2012/12/07/2806483.html) (查看磁盘大小占用情况)

详见参考

CentOS7 默认的文件系统是 **xfs**,CentOS6默认的文件系统是ext4

xfs更加优秀:https://yq.aliyun.com/articles/460715

1. 采用B+树作为表结构
2. 64位

**tmpfs**:一种类似于ramdisk的文件系统https://baike.baidu.com/item/tmpfs

## May 28: [du 查看文件或者目录的大小](https://www.cnblogs.com/peida/archive/2012/12/10/2810755.html)

## May 29: [sort命令](http://man.linuxde.net/sort)

1. 可以从标准输入 或者文件得到输入
2. 可以指定field,等条件进行排序

## May 30: ln 链接命令

[参考一](https://cyc2018.github.io/CS-Notes/#/notes/Linux?id=链接)

[参考二](http://man.linuxde.net/sort)

## Sep 13: vmstat命令

<https://www.cnblogs.com/ggjucheng/archive/2012/01/05/2312625.html>

vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix最喜爱的命令,一个是Linux/Unix都支持,二是相比top,我可以看到整个机器的CPU,内存,IO的使用情况,而不是单单看到各个进程的CPU使用率和内存使用率(使用场景不一样)

### 使用:

vmstat param1 param2

param1表示采样频率

param2表示采样次数,省略则表示一直采样

如:vmstat 2 表示 两秒采样一次,一直监控状态直到取消命令

```bash
[root@vultr ~]# vmstat 2
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 157588 14004 317880 0 0 0 6 5 17 0 0 99 0 0
0 0 0 157596 14012 317884 0 0 0 24 1039 137 0 0 100 0 0
0 0 0 157596 14012 317892 0 0 0 0 1034 132 1 0 99 0 1
0 0 0 158868 14012 317888 0 0 0 0 1040 131 0 0 100 0 0

参数解析:

procs下两个参数 r 和 b

r 表示运行队列(就是说多少个进程真的分配到CPU),我测试的服务器目前CPU比较空闲,没什么程序在跑,当这个值超过了CPU数目,就会出现CPU瓶颈了。这个也和top的负载有关系,一般负载超过了3就比较高,超过了5就高,超过了10就不正常了,服务器的状态很危险。top的负载类似每秒的运行队列。如果运行队列过大,表示你的CPU很繁忙,一般会造成CPU使用率很高

b 表示阻塞的进程,这个不多说,进程阻塞,大家懂的

memory下参数 swpd,free,buff,cache

swapd 已经使用的虚拟内存大小

free 空闲的物理内存的大小

buff Linux/Unix系统是用来存储,目录里面有什么内容,权限等的缓存

cache cache直接用来记忆我们打开的文件,给文件做缓冲

当内存使用不够的时候,buffer/cached会很快地被使用 (空闲内存 应该是 free+buff+cache)

swap下参数:si,so

si,swap input 每秒 swap空间的换入,swap频繁交换时 表示 内存不够使用

so,swap output 每秒swap空间的换出,swap频繁交换时 表示 内存不够使用

io 下参数:bi,bo

bi, block input 块设备每秒接收的块数量,也即从磁盘角度来说其输入,内存的输出

bo, block output 块设备每秒输出的块数量,也即从磁盘角度来说其输出,内存的输入

System下的参数:in,cs

in: interrupt , 系统的中断次数

cs: context swap, 系统上下文切换次数,一般而言越低越好,上下文切换消耗资源大,如果太高,需要调低线程数量

CPU下的参数:us,sy,id,wt

us:user,用户使用的CPU时间

sy:system,系统进程使用的CPU时间

id:idle,空闲的CPU时间

wt:wait, 等待IO的CPU时间

Sep 13: top 与 ps 命令查看线程

排查问题时,除了需要定位到进程,还需要定位到进程中的线程,通过ps 与 top 命令可以定位到线程

ps -Tp [pid]

top -Hp [pid]

#问题排查

QPS,TPS,吞吐量

TPS:Transactions Per Second(每秒传输的事物处理个数),即服务器每秒处理的事务数。TPS包括一条消息入和一条消息出,加上一次用户数据库访问

QPS:每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准

系统吞吐量几个重要参数:QPS(TPS)、并发数、响应时间

QPS(TPS)= 并发数/平均响应时间

场景

系统突然运行缓慢,CPU 100%

应急操作

  1. 保存现场:jstack,内存信息等
  2. 重启系统,保证可用

可能原因以及解决办法

以下两个原因会导致系统不可用:

  • Full GC频繁发生的可能原因与措施
    • System.gc()的调用,尽管只是建议FullGC,但是仍可能发生FullGC
      • 处理方式:-XX:+ DisableExplicitGC来禁止RMI调用System.gc
    • old generation 空间不足:1. 大对象 2.有许多逻辑上不使用的对象,仍有引用指向
      • 处理方式:1. 增大老年代空间 2. 将不再使用的对象的引用置为null 3. 降低大对象的创建
    • 永久代:Java 1.8之前方法区实现为永久代,加载的类、反射的类和调用的方法较多时 发生FullGC
      • 处理方式:1. 增大永久代空间 2. 避免不必要的类的创建
      • Java 1.8之后 永久代改为元空间:1. 元空间为本地内存 2. 元空间不需要GC,有专门的回收操作,class对象的生命周期同类加载器一致 (1.8之后不存在方法区导致的Full GC)
    • 空间担保失败:新生代 回收时 利用老年代空间担保,如果老年代空间不足,担保失败,进行Full GC
      • 处理方式:增大 survivor区 以及 老年代空间大小
  • 线程问题
    • 代码正在执行计算密集型操作 – jstack分析线程 (正常)
    • 死锁 – jstack分析线程

Full GC问题的排查步骤

  1. 通过top/ps 查看到占用CPU较多的进程 PID
  2. 查看导致进程占用CPU较多的线程的 PID (十进制)
    1. top -Hp [pid]
    2. ps -Tp [pid]
  3. 使用jstat -gc pid 查看gc情况,查看GC的增长情况
  4. 通过JVM jstack 命令查看JVM线程状态 (其中nid 为16进制)
    1. 如果是Full GC次数过多,那么通过jstack得到的线程信息会是类似于VM Thread之类的线程
    2. 如果是代码中有比较耗时的计算,那么我们得到的就是一个线程的具体堆栈信息
  5. 使用jmap -dump:format=b,file=heapDump 3331生成堆转储文件
  6. 使用jhat或者可视化工具(Eclipse Memory Analyzer 、IBM HeapAnalyzer)分析堆情况
  7. 结合代码解决内存溢出或泄露问题

线程问题的排查步骤

  1. 使用jps查看线程ID
  2. 使用jstack pid:查看线程情况
如果觉得有用的话,打赏我吧~