libc
Memory Protection
参见:文档。
参考链接。
thread apply [threadno] [all] args
- 将命令传递给一个或多个线程,参见链接。
比如,thread apply all continue
表示将continue
命令传递给所有线程,也就是让所有线程都继续运行。
rbreak
- Set a breakpoint for all functions matching REGEXP. 参考链接。
e.g. rbreak file.C:.*
- 给file.C的所有函数加上断点。
info
attach
- 连接到正在运行的进程。与gdb -p
效果相同。
detach
- 取消连接的进程。
handle <signal> print pass nostop
- 捕获信号(比如SIGSEGV
)并且忽略它。handle <signal nostop
。
set
- 修改变量的值,比如set x=10
(或set var x=10
)将变量x
的值改为10
。参考博客。
show directories
print
- gdb默认设置打印字符串的长度为200;更改打印最大长度:set print elements <number-of-elements>
,0
表示unlimited.
ptype <variable name>
- 打印变量类型。
finish
- 从函数中返回,并打印函数返回值(即使函数的return语句很复杂,也可以获取返回值)。
见链接
添加断点:
1 | break file:line_no |
查看断点:
1 | info break |
删除第2个断点:
1 | delete 2 |
break ... if cond
1 | try...catch |
1 | set max-value-size bytes |
打印字符长度限制
gdb默认设置打印字符串的长度为200;更改打印最大长度:set print elements
gdb命令:gcore
。
WSL指Windows虚拟机。
解决方法:
1 | sudo add-apt-repository ppa:ubuntu-support-team/gdb |
This is due to kernel hardening in Linux; you can disable this behavior by echo 0 > /proc/sys/kernel/yama/ptrace_scope
or by modifying it in /etc/sysctl.d/10-ptrace.conf
.
How to solve “ptrace operation not permitted” when trying to attach GDB to a process?
By default, when a program forks, gdb will continue to debug the parent process and the child process will run unimpeded.
If you want to follow the child process instead of the parent process, use the command set follow-fork-mode
.
set follow-fork-mode mode
Set the debugger response to a program call of fork
or vfork
. A call to fork or vfork creates a new process. The mode argument can be:parent
The original process is debugged after a fork. The child process runs unimpeded. This is the default.child
The new process is debugged after a fork. The parent process runs unimpeded.ask
gdb 会提示让你选择 parent
还是 child
。
show follow-fork-mode
Display the current debugger response to a fork or vfork call.
On Linux, if you want to debug both the parent and child processes, use the command set detach-on-fork.
set detach-on-fork mode
Tells gdb whether to detach one of the processes after a fork, or retain debugger control over them both.on
The child process (or parent process, depending on the value of follow-fork-mode) will be detached and allowed to run independently. This is the default.off
Both processes will be held under the control of gdb. One process (child or parent, depending on the value of follow-fork-mode) is debugged as usual, while the other is held suspended.
show detach-on-fork
Show whether detach-on-fork mode is on/off.
If you issue a run command to gdb after an exec call executes, the new target restarts. To restart the parent process, use the file command with the parent executable name as its argument. By default, after an exec call executes, gdb discards the symbols of the previous executable image. You can change this behaviour with the set follow-exec-mode command.
set follow-exec-mode mode
Set debugger response to a program call of exec. An exec call replaces the program image of a process.
follow-exec-mode can be:
new
gdb creates a new inferior and rebinds the process to this new inferior. The program the process was running before the exec call can be restarted afterwards by restarting the original inferior.
For example:
1 | (gdb) info inferiors |
same
gdb keeps the process bound to the same inferior. The new executable image replaces the previous executable loaded in the inferior. Restarting the inferior after the exec call, with e.g., the run command, restarts the executable the process was running after the exec call. This is the default mode.
For example:
1 | (gdb) info inferiors |
You need to enable logging:
1 | (gdb) set logging on |
记录输入的命令:
1 | (gdb) set trace-commands on |
gcc 的输入文件和库是从左往右处理的。也就是说,以下命令是错误的:
1 | gcc -L. -la main.cc |
链接器处理到某个目标文件(如 main.cc 编译后的目标代码)时,如果遇到未解析的符号(比如 f() ),
它会从接下来的库中查找这些符号。因此顺序非常重要。
这里,-L. -la 选项在 main.cc 之前,链接器会首先尝试从 liba.so 中查找引用的符号,
但是,因为此时 main.cc 还未被处理,所以链接器还不知道有对 liba.so 中的函数 f() 的引用。
到了 main.cc ,链接器解析出引用,但它不会回头再去 liba.so 中查找,导致报错:”undefined reference to f()”。
正确的命令如下:
1 | gcc main.cc -L. -la |
注意:liba.so 的指定必须去掉 lib 和 .so ,也就是说不允许直接指定“库文件名”,而是只能指定“库名”。
如果想直接指定库文件名,那么应该把 liba.so 当成输入文件:
1 | gcc main.cc ./liba.so |
参考:官方文档。
参考:
属性列举:
format (archetype, string-index, first-to-check)
format 属性,指定函数采用 printf、scanf、strftime 或 strfmon 风格的参数,
这些参数应根据格式字符串(format string)进行类型检查(type-checked)。
类型检查发生在编译期。
举例:
1 | extern int |
archetype
决定format string应该如何解释。printf
、scanf
、strftime
或strfmon
(也可以使用__printf__
、__scanf__
、__strftime__
或__strfmon__
)。string-index
指定哪个参数是format string(从1开始)。first-to-check
指定format string对应的第一个参数的序号。vprintf
),该参数指定为0
。在这种情况下,编译器仅检查format string的一致性。对于strftime
格式,该参数必须为0
。-save-temps
: 可以保留所有中间文件,例如预编译文件、汇编文件、目标文件等。ulimit
1 | #查看配置 |
ulimit
只对当前终端有效。
以下两种方法对所有用户和终端有效:
/etc/security/limits.conf
中设置(redhat衍生系linux)。/etc/profile
中的这一行: 1 | # No core files by default |
见链接。
Read /usr/src/linux/Documentation/sysctl/kernel.txt.
core_pattern is used to specify a core dumpfile pattern name.
在系统启动时,Apport(crash reporting service)会生成配置文件/proc/sys/kernel/core_pattern
。参考这里。
Apport uses /proc/sys/kernel/core_pattern
to directly pipe the core dump into apport
:
1 | $ cat /proc/sys/kernel/core_pattern |
Note that even if ulimit
is set to disabled core files (by specyfing a core file size of zero using ulimit -c 0
), apport
will still capture the crash.
For intercepting Python crashes it installs a /etc/python*/sitecustomize.py
to call apport on unhandled exceptions.
其中,/usr/share/apport/apport
是一个python脚本。
以下是core_pattern文件的参数说明(参考Linux Manual Page:man core
):
1 | %c - Core file size soft resource limit of crashing process (since Linux 2.6.24). |
Apport的拦截组件默认是关闭的:
Apport itself is running at all times because it collects crash data for whoopsie (see ErrorTracker). However, the crash interception component is still disabled. To enable it permanently, do:
1 | sudo nano /etc/apport/crashdb.conf |
… and add a hash symbol # in the beginning of the following line:
'problem_types': ['Bug', 'Package'],
To disable crash reporting just remove the hash symbol.
见链接。
/proc/sys/kernel/core_uses_pid可以控制产生的core文件的文件名中是否添加pid作为扩展,如果添加则文件内容为1,否则为0;
/proc/sys/kernel/core_pattern可以设置格式化的core文件保存位置或文件名:
1 | $ cat /proc/sys/kernel/core_pattern |
你可以用下列方式来完成:
1 | #查看所有sysctl所有变量的值。 |
这些操作一旦计算机重启,则会丢失,如果你想持久化这些操作,可以在 /etc/sysctl.conf文件中增加:
1 | kernel.core_pattern=/tmp/core%p |
加好后,如果你想不重启看看效果的话,则用下面的命令:
1 | sysctl -p /etc/sysctl.conf |
参考资料:
Linux Manual Page: man core
SEE ALSO
bash(1), coredumpctl(1), gdb(1), getrlimit(2), mmap(2), prctl(2), sigaction(2), elf(5), proc(5), pthreads(7), signal(7), systemd-coredump(8)
参考链接。
参考博客
1 | gcc -E test.c -o test.i |
编译
编译是将高级语言(例如C、C++、Jave等)代码转换成机器码的过程。
编译可以分成多个阶段,包括词法分析、语法分析、语义分析、优化和代码生成。
编译器首先将源代码转换一种中间表示(通常是汇编代码或字节码),然后再将其转换为目标机器的机器代码。
经过编译的代码通常是二进制的,可以直接在目标机器上执行。
先生成汇编代码:
1 | gcc -S test.i -o test.s |
汇编
将汇编代码转成机器码。
1 | gcc -c test.s -o test.o |
链接
该目标文件与其他目标文件、库文件、启动文件等链接起来生成可执行文件。
1 | gcc test.o -o test |
Note: 可以使用 -save-temps
选项以保留编译过程中的所有中间文件:
1 | gcc -save-temps test.c |
Name mangling (C++ only)
: 名称修饰,也称为名称重整、名称改编。参见链接1、2。
参考:man ld.so
PATH
LD_LIBRARY_PATH
LD_PRELOAD
参考:man ld.so
, man vdso
, man elf
, scanelf
ld(1), ldd(1), pldd(1), sprof(1), dlopen(3),getauxval(3), elf(5), capabilities(7),
rtld-audit(7), ldconfig(8), sln(8), vdso(7), as(1), elfedit(1), gdb(1), nm(1),
objcopy(1), objdump(1), patchelf(1), readelf(1), size(1), strings(1), strip(1),
execve(2), dl_iterate_phdr(3), core(5), ld.so(8)
ldconfig
配置动态连接器(dynamic linker)的运行时绑定(dynamic bindings)。
如果你刚刚安装好共享库,可能需要运行ldconfig:
sudo ldconfig
通常需要超级用户来运行ldconfig,因为可能对需要某些root用户所有的目录和文件有写入权限。
lddconfig 为从以下目录找到的共享库创建必要的 links 和 cache :
command line指定的目录;
/etc/ld.so.conf文件中指定的目录;
受信任的目录: /lib, /lib64, /usr/lib, /usr/lib64 。
该 cache 被运行时连接器(run-time linker) ld.so 或 ld-linux.so 使用。
ldconfig 尝试基于该库连接的 C 库来推断 ELF 库(比如 libc5 或 libc6/glibc)的类型。
一些现有的库没有包含足够的信息来推断其类型。
因此, /etc/ld.so.conf 文件格式允许指定期望的类型。
这只在这些 ELF 库不能被解决的情况下使用。
ldconfig 期望的符号链接有某种特定的形式,比如:
libfoo.so -> libfoo.so.1 -> libfoo.so.1.12
其中,中间的文件 libfoo.so.1 是库的 SONAME 。
如果不遵循这种格式可能会导致升级后的兼容性问题。
ldd
描述:
ldd调用标准动态连接器(见 ld.so(8)),并且将环境变量 LD_TRACE_LODADED_OBJECTS 为 1 。
这会让动态连接器检查程序的动态依赖,并且寻找(根据 ld.so(8) 描述的规则)
和加载满足这些依赖的目标。对于每一条依赖,
ldd 显示匹配的目标的位置和其载入处的16进制地址。
(linux-vdso和ld-linux共享依赖是特殊的;见vdso(7)和ld.so(8))
安全性:
注意,在某些情况下,一些版本的ldd可能会尝试通过直接运行程序(可能导致程序中的ELF解释器
或程序本身的运行)来获取依赖信息。
因此,永远不要在不受信任的可执行文件上使用ldd,因为会导致随意代码的运行。更安全替代方法为:
$ objdump -p /path/to/program | grep NEEDED
注意,这种替代方法只会显示该可执行文件的直接依赖,而ldd显示该可执行文件的整个依赖树。
解释ldd的输出:
$ ldd -v libibsupport_real.so
./libibsupport_real.so: /usr/lib64/libibverbs.so.1: version `IBVERBS_1.8' not found (required by ./libibsupport_real.so)
linux-vdso.so.1 => (0x00002ad3e49e3000)
libibverbs.so.1 => /usr/lib64/libibverbs.so.1 (0x00002ad3e589b000)
...
Version information:
./libibsupport_real.so:
libgcc_s.so.1 (GCC_3.0) => /usr/lib64/libgcc_s.so.1
libibverbs.so.1 (IBVERBS_1.8) => not found
libibverbs.so.1 (IBVERBS_1.1) => /usr/lib64/libibverbs.so.1
...
/usr/lib64/libnl-3.so.200:
libm.so.6 (GLIBC_2.2.5) => /usr/lib64/libm.so.6
...
在"Version information"中,"libgcc_s.so.1 (GCC_3.0) => /usr/lib64/libgcc_s.so.1"表示:
"libgcc_s.so.1"指定一个shared library的名字(libgcc_s.so.1是GCC runtime library的一部分),该shared library为"./libibsupport_real.so"所依赖;
"(GCC_3.0)"表明"libgcc_s.so.1"需要3.0版本及以上的GNU Compiler Collection (GCC);
"=>"指出满足依赖的shared library;
"/usr/lib64/libgcc_s.so.1"是满足要求的shared library的路径。
sprof
objdump
[-p|--private-headers]
[-x|--all-headers]
readelf
[-d|--dynamic]
/lib/ld.so
Run-time linker/loader.
/etc/ld.so.conf
File containing a list of directories, one per line, in which to search for libraries.
/etc/ld.so.cache
File containing an ordered list of libraries found in the directories specified in /etc/ld.so.conf, as well as those found in the trusted directories.
The trusted directories:
/lib
/lib64
/usr/lib
/usr/lib64
ld.so
名字
ld.so, ld-linux.so - 动态连接/加载器。
简介
动态连接器可以被间接运行或直接运行。
间接运行:
运行某些动态连接程序或共享库。在这种情况下,不能向动态连接器传递命令行选项;并且在ELF情况下,存储在程序的.interp section中的动态连接器被执行。
直接运行:
/lib/ld-linux.so.* [OPTIONS] [PRAGRAM [ARGUMENTS]]
描述
ld.so 和 ld-linux.so* 寻找和加载程序所需的共享对象(共享库),准备程序的运行,然后运行它。
如果在编译期没有向 ld(1) 指定 -static 选项,则Linux二进制文件需要动态连接(在运行时连接)。
参考:man ldconfig
参考:SONAME Wiki
GNU linker使用 -hname 或 -soname=name 来指定该库的library name field。
在内部,linker会创建一个 DT_SONAME field并且用 name 来填充它。
1 | #Use ld: |
1 | ln -s libexample.so.1.2.3 libexample.so.1 |
1 | #Use objdump |
my_printf
:1 | #include <stdio.h> |
VERSION_1
:1 | VERSION_1 { |
version_script.txt
为version-script:1 | gcc -shared -Wl,--version-script=version_script.txt -o libexample.so example.o |
其中,-Wl,
引出连接器选项。
readelf -sW libexample.so
查看函数my_printf
的版本号(”VERSION_1”):1 | Symbol table '.dynsym' contains 8 entries: |
objdump -T libexample.so
nm -D libexample.so
1 | #include <stdio.h> |
例如,version_script.map文件如下:
1 | VERS_1.0 { |
VER_1.1继承了VER_1.0的全部符号,同时VER_1.1可以增加或修改符号。
VER_1.0:第一个版本,导出foo符号;
VER_1.1:第二个版本,引入foo_v2,并重新导出foo;
有如下简单代码:
1 | // file: main.cc |
正常编译:
1 | g++ main.cc -o a.out |
查看符号:
1 | strings a.out |
你会发现其中有一些版本信息:
1 | ... |
这是因为编译器和链接器生成库或可执行文件时,会根据系统上安装的glibc版本(因为库和可执行文件依赖glibc),
为库或可执行文件的函数符号附加上特定的版本信息。
为了保证向下兼容,glibc通过符号控制保留了多个版本的符号,支持老版本的软件能在较新的系统上运行。
例如,如果某个函数在glibc2.2.5中引入,它可以继续保留在之后的版本中,但符号标记为GLIBC_2.2.5。
ELF - Executable and Linking Format.
ELF描述了normal executable files、relocatable object files、core files和shared objects的格式。
参考:man elf
, 博客:elf介绍。
参考:程序员的自我修养, man ld
GCC的提供了不同的方法指定链接的共享库:
l<link_name>
参数
指定需要链接的共享库lib
l:<filename>
参数
通过文件名指定共享库,参考LD手册
全路径指定
Wl,-static
参数
指定查找静态库,通过-Wl,-Bdynamic恢复成动态库查找
参考:man ld
ld - The GNU linker
选项:
-rpath=dir
添加一个目录到运行时库搜寻路径中。
gcc通过 -Wl
前缀指定链接器选项,例如:
gcc -Wl,--start-group foo.o bar.o -Wl,--end-group
gcc -Wl,-rpath,'$ORIGIN/../lib'
Answer:
ldd /path/to/program
objdump -p /path/to/program | grep NEEDED
lddtree
(from pax-utils
) or readelf -d /bin/ls | grep 'NEEDED'
lsof -p PID | grep mem
1 | $ pidof nginx |
strace -e trace=open myprogram
ldd
and lsof
show the libraries loaded either directly or at a given moment. They do not account for libraries loaded via dlopen
(or discarded by dlclose
). You can get a better picture of this using strace
.
pmap <pid> -p
生成so时,链接器不会寻找其so依赖;executable会寻找so的依赖关系。换句话说,即使so生成过程不报错,但是executable生成时可能会报错。
生成so时,如果引用了其他 so ,只要 include 其他 so 的头文件,引用头文件中的符号时,就能编译通过。但是这样生成的 so 没有加上对应符号的依赖。
此时用 readelf -s 查看对应的符号,其 type 为 NOTYPE 。
1 | $ readelf -sW libb.so |
如果加上对应 -la 选项,就会从 liba.so 中寻找依赖的符号,如果找到,则添加进入 so 的依赖项中。当运行时则会加载 liba.so ,否则运行时不会加载。
用 readelf -s 查看对应的符号,其 type 不再时 NOTYPE ,而是 FUNC (如果该符号是一个函数的话)。
1 | 6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Z1fv |
如果没有找到符号,或者说 liba.so 中根本没有实现这个函数,那么其 type 依然是 NOTYPE ,此时也不会报错。
注意:如果只是 include 头文件,也就说只有某个符号的声明,并没有其定义或引用它,那么 so 中不会生成其信息。
解释:libxxx.so
引用了一个 GLIBCXX_3.4.30
的符号(可能是全局变量或函数),但是在系统的 /usr/lib/x86_64-linux-gnu/libstdc++.so.6
中没有这个版本的符号。
1 | $ strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep 'GLIBCXX_3.4.' |
这往往是因为原始的版本中,libxxx.so
是在一台机器中编译的,此时将该机器的 GLIBCXX_3.4.30
符号编译到其中了。但是运行时的机器是另一台,该机器上
不存在 GLIBCXX_3.4.30
版本,所以运行时报错。
或者,因为环境变量的配置错误,编译时和运行时引用的 libstdc++.so.6
不是同一个,这也会导致运行时可能找不到编译时的 GLIBCXX_3.4.30
版本。
可以在源文件中使用指定的版本(使用运行时的版本,比如 GLIBCXX_3.4.11
):
1 | $ objdump -T /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep condition_variable | c++filt |
可以确定符号为 _ZNSt18condition_variable4waitERSt11unique_lockISt5mutexE
,版本为 GLIBCXX_3.4.11
。
在源文件中指定版本
1 | /** 指定特定版本的符号 START */ |
编译:
1 | g++ symver.cpp |
验证符号版本:
1 | $ strings a.out | grep condition_variable | c++filt |
C++有一个缺陷,请看以下代码:
1 | //cpp defeat: basic_string::_M_construct null not valid |
其中,fun(0)
的0
会被视为const char*
类型,也就是nullptr
,所以在编译期可以通过。
但是运行期会触发string
对象的构造错误“basic_string::_M_construct null not valid”。
隐蔽一点的代码:
1 | char * get_a_string() { |
valgrind
参考:
博客
文档
可以使用PostScript查看图形化结果
Oracle Developer Studio:
1 | $ /usr/bin/time -p ls |
Or,
1 | $ time ls |
其中(参考链接),
1 | $ type -a time |
Function’s CPU time:
* Inclusive time: total cpu time, include all functions it calls.
* Exclusive time: only the time used by the function itself, exclusive all its children.
Refer to [here](https://stackoverflow.com/questions/15760447/what-is-the-meaning-of-incl-cpu-time-excl-cpu-time-incl-real-cpu-time-excl-re/74426370).
Wall time: total time the process used, containing IO time.
CPU usage (CPU利用率) = CPU time / Wall time.
real/user/system time
Refer to here.
CPU 时间可能大于墙上时间:
这是因为 CPU 时间是所有 CPU 核的运行时间的累加和,墙上时间则是实际的时间。此时 CPU 利用率大于 100%. (这是自己的理解)
TODO: Is CPU time in flame graph sum of all the CPU time? Or is it the wall time when CPU works?
1 | (gdb) breakpoint exit |
Enable coredump: how to do
1 | ulimit -c unlimited |
Where is the core dumped file:
1 | grep 'kernel.core_pattern' /etc/sysctl.conf |
Example:
1 | strace -f -o strace.log -tt -y -yy -e trace=desc,process,network |
Refer to here
-e trace=ipc – communication between processes (IPC)
-e trace=memory – memory syscalls
-e trace=network – network syscalls
-e trace=process – process calls (like fork, exec)
-e trace=signal – process signal handling (like HUP, exit)
-e trace=file – file related syscalls
-e trace=desc – all file descriptor related system calls
mkdocs.yml
文件是 MkDocs 文档生成器的配置文件。
示例:mkdocs.yml
该文件中的 theme
部分用于指定用于生成文档的主题。
在这种情况下,使用的主题是 Material。 name
字段指定主题的名称,而 custom_dir
字段指定包含主题自定义内容的目录。 features
字段指定可以为主题启用的可选功能列表。
以下是在此配置文件中列出的可选功能:
announce.dismiss
: 启用可关闭的公告横幅,显示在文档的每个页面顶部。content.action.edit
: 在每个页面上启用“编辑”按钮,以便用户可以轻松编辑页面内容。content.action.view
: 在每个页面上启用“查看源代码”按钮,以便用户可以查看页面的源代码。content.code.annotate
: 启用代码注释功能,使用户可以添加注释以解释代码。content.code.copy
: 启用代码复制功能,使用户可以轻松复制代码。content.tooltips
: 启用工具提示功能,使用户可以在鼠标悬停时查看有关页面元素的信息。navigation.footer
: 在每个页面上启用页脚导航栏。navigation.indexes
: 启用索引导航栏,使用户可以轻松浏览文档中的索引。navigation.sections
: 启用部分导航栏,使用户可以轻松浏览文档中的各个部分。navigation.tabs
: 启用选项卡导航栏,使用户可以轻松浏览文档中的各个选项卡。navigation.top
: 在每个页面上启用顶部导航栏。navigation.tracking
: 启用导航跟踪功能,使用户可以跟踪他们在文档中的位置。search.highlight
: 启用搜索结果高亮显示功能。search.share
: 启用共享搜索结果功能,使用户可以轻松共享搜索结果。search.suggest
: 启用搜索建议功能,使用户可以在输入搜索查询时获得建议。toc.follow
: 启用目录跟随功能,使目录始终保持可见。palette
字段指定了一个颜色方案,该方案包含以下内容:
scheme
: 指定颜色方案的名称。primary
: 指定主要颜色。accent
: 指定强调颜色。toggle
: 指定切换到暗模式时使用的图标和名称。第一个方案名为 default,其中主要颜色和强调颜色均为 indigo。切换到暗模式时,使用的图标为 material/brightness-7,名称为“切换到暗模式”。
第二个方案名为 slate,其中主要颜色和强调颜色均为 indigo。切换到亮模式时,使用的图标为 material/brightness-4,名称为“切换到亮模式”。
font 字段指定了用于文本和代码的字体。在此配置文件中,文本字体为 Roboto,代码字体为 Roboto Mono。 favicon 字段指定了网站图标的路径。 icon 字段指定了网站标志的路径。
favicon 和 icon 是网站的两个不同元素。
favicon 是网站的图标,通常显示在浏览器标签页上。它可以是一个小的图像文件,通常是 .ico 格式。在 mkdocs.yml 文件中,可以使用 favicon 字段来指定网站图标的路径。
icon 是网站的标志,通常显示在网站的标题栏或页眉中。它可以是一个图像文件,例如 .png 或 .jpg 文件。在 mkdocs.yml 文件中,可以使用 icon 字段来指定网站标志的路径。
这里列出了三个插件:blog、search和minify。其中,blog插件用于支持博客功能,search插件用于支持搜索功能,而minify插件用于压缩HTML文件。在search插件中,separator参数指定了搜索时的分隔符,这里的分隔符包括空格、连字符、逗号、冒号、等号、感叹号、方括号、括号、引号、反引号和斜杠等。
analytics参数用于指定网站分析服务提供商和属性ID,例如衡量网站流量。
See the doc.
refer to:
/proc
: 查看手册 man proc
。
/proc/self/exe
: 是指向当前进程的程序文件的软链接。
/proc/<pid>/exe
: 是指向进程<pid>
的程序文件的软链接。
/proc/[pid]/status
:可查看进程的内存使用峰值等信息,关键字为”VmHWM”、”VmPeak”、”VmRSS”。
/proc/[pid]/stat
:get current memory
/dev/shm
:
What Is /dev/shm And Its Practical Usage
1 | $ df -h |
Sample outputs:
1 | Filesystem Size Used Avail Use% Mounted on |
本小节内容来自 参考链接 。
Linux上的分区指:存储设备中划分出来的一个片段,该片段与其他片段逻辑上分离,好比一个个独立的房间。
分区表存储各个分区的元数据,比如起始位置、终止位置、大小等。
有两种主要的分区表类型,MBR(older)和GPT(newer):
Partition tables | Maximum primary partitions | Maximum size for each partition | Security | Operating system Support |
---|---|---|---|---|
Master Boot Record (MBR) | 4 | 2TB | No such security features | Supports most modern OS |
Guid Partition Table (GPT) | No such limit | 18 Exabytes | CRC32 checksum mechanism to verify the integrity of files | Supports most modern OS |
从上表可以很明显地看出,为什么GPT更推荐。
文件系统是我们在每个分区中管理数据的方式。它负责索引、存储、检索、命名文件和维护文件的元数据(文件所有者、大小、权限等)。存储在分区中。
一个文件保存在多个连续的 扇区(sector) 中,现代每个扇区大约为4096字节。
文件系统负责组织哪些扇区准备好使用了、一个文件必须存储在哪个扇区、哪个扇区存储了什么文件。
如果没有这种组织,就无法无法检索任何文件,因为系统无法得知文件的位置(block,块)。
主要的文件系统分类:
文件分配表(FAT,File Allocation Table)是Microsoft开发的第一个文件系统。
从1997发布之后,有多个版本,称为FAT12、FAT16、FAT32,连续地增加了最大支持文件大小(file size)和驱动器大小(drive size)。
FAT32允许的最大文件大小为4Gb。直至WindowsXP,FAT32是默认的文件系统,之后被NTFS取代。
虽然FAT非常基础,但是它支持几乎所有的设备和操作系统。
注: 驱动器(drive),是一个能存储和读取非易失信息的位置,比如磁盘(disk)或光盘(disc)。
如下图,驱动器A:是一个软盘(floppy drive),
驱动器C:是主硬盘(primary hard drivce),
驱动器D:和E:是分区,F:是CD-ROM。
CD-ROM常常是最后一个盘符(drive letter)。
在多数情况下,硬盘是C:驱动器,CD-ROM或其他光盘是D:驱动器。
新技术文件系统(New Technology File System,NTFS)是FAT的现代替代者。
除了支持高达16EB(大于170亿GB)的驱动器大小和256TB的单文件大小外,还支持日志系统(journaling system)。
Linux的扩展文件系统(extended file system)或ext于1992年发布。之后有了3次更新:
ext2引入了文件属性(文件权限),ext3引入了日志功能(journaling)。
ext4对ext2和ext3向后兼容,增加了存储限制和一些性能调整。
可以支持高达1EB的卷(volumn),单个文件可以达16TB。
ext4也引入了延迟内存分配的概念,即在文件被强制刷新到存储设备时才为其分配扇区。
这提高了CPU的性能并减少了坏的扇区。
今天几乎所有的现代Linux发行版都使用ext4作为默认的文件系统。
ZFS
Btrfs
下图是一个分区和文件系统的层次结构示例:
我有一个500GB的SSD,分成3个分区(boot、home、root),使用GPT作为分区表。
我没有分出swap分区。所有的分区都跑在ext4文件系统上。
在一个双启动(dual-booted)存储设备(Windows和Linux)上,还有几个适用于Windwows的NTFS分区。
你可以使用以下命令在任意存储设备上查看分区:
1 | lsblk |
更多资源请访问:
挂载:使设备上的文件和目录可以通过文件系统访问的一个过程。见维基百科。
挂载点:A mount point is a location in the partition used as a root filesystem.
lsblk
lsblk [options] [device...]
list all avaivable or specified block devices.
Reads the sysfs filesystem to gather information.
df
df [OPTION]... [FILE]...
report file system disk space usage on which each FILE resides.
df -T 打印文件系统的类型。
du
du [OPTION]... [FILE]...
estimate file space usage.
quota
quota -s -u user...
display users' disk usage and limits.
quota reports the quotas of all the filesystems listed in /etc/mtab.
For filesystems that are NFS-mounted a call to the rpc.rquotad on the server machine is performed to get the information.
-s, --human-readable
repquota
prints a summary of disc usage and quotas for the specified file system.
mount
lsof - list open files
https://unix.stackexchange.com/questions/11238/how-to-get-over-device-or-resource-busy