这两天办公用的 Ubuntu 总是在内存将用尽的时候死机,所有的界面卡住不同,进 tty 用 top 看一眼后发现 kswapd0
这个进程竟然占用 90~100% 左右的 CPU,网上一查说这个进程是用来管理虚拟内存的。
一般的 Linux 都会有 RAM,swap, 和 EXT4 这几个部分,EXT4 分区就是用来存放一般的文件,可以在机械硬盘或者 SSD 上划分出 ext4 分区来保存文件,相对 RAM(内存)来说要稍微慢一些,RAM 就是日常所说的内存,用来做程序运行时的高速缓存,而 SWAP 是交换分区,一般在物理内存比较小的机器上会划分一块物理磁盘来作为 swap 分区。
swap 分区是一款虚拟的 RAM,一般在 HDD/SSD 上,当运行比较小的物理内存时,可能经常缺内存,那么系统就会使用 swap 分区,将物理内存中的内容搬迁到 swap 分区中暂存。当可用物理内存比较小的时候,kswapd0 进程就会将相对比较不常用的程序移动到 swap 分区中,这个时候就可能造成这些程序比较卡顿。加入又一台机器物流内存是 4G,而要运行一个需要 5G RAM 的游戏,那么至少有 1G 的内存会放到 swap 分区中。kswapd0 移动内存的过程就会造成 CPU 的大量使用。要解决这个问题有这样几个方式。
在网络上有些教程会提醒用户,当计算机使用了比较大的物理内存的时候,就不需要划分 swap 分区了,一定程度上这种说法也没问题,但是如果 disable swap 分区后,如果遇到程序内存泄漏或者物理内存用完的情况,那么整个计算机就会进入卡死状态。所以推荐还是不要禁用 swap,虽然 swap 分区不会有 RAM 那么快,但是当 RAM 耗尽的时候,swap 分区可以提供一层额外的保护。如果对 swap 比较感兴趣,可以参考这里 阅读更多的相关知识。1
在 askubuntu 的回答中有句话说的很好
Just realize that the SWAP is a failsafe for the RAM.
failsafe 及时发生了故障也要有故障保护机制,否则系统就会 fail.
配置 /etc/sysctl.conf
文件,来告诉 kswapd0 进程只有当物理内存用尽的时候再做移动内存的事情
echo vm.swappiness=0 | sudo tee -a /etc/sysctl.conf
这里 0
表示物理内存还剩余的百分比,这个值的取值范围是 0-100,配置 0 也就意味着只有当没有物理内存可用时再执行 kswapd0.
降低或者减少物理内存的使用,也可以降低 kswapd0 过于频繁执行的问题。
一劳永逸的解决内存短缺的问题。也就是换内存条。
因为工作的 Ubuntu 是从一盘机械硬盘复制到 SSD 中的,当时 swap 分区没有划分,如果要手动添加 swap 分区可以如下操作。
根据详细的步骤,分区,以及格式化参考之前的文章
编辑 /etc/fstab
文件,增加新的 swap 分区:
sudo vi /etc/fstab
增加类似这样一行:
UUID=735b3be3-779c-4d21-a944-b033225f3ab4 none swap sw 0 0
分区的 UUID,可以通过 blkid
命令来获取:
sudo blkid /dev/sda2
假设 /dev/sda2
就是划分的新的 swap 分区。
已经忘记了什么契机,BookStack 就存在了我的 ToDo List 中,一直想要找一款能够快速记录一些常用到的,但是却不太容易记住的东西,原来的方法就是用 markdown + git, 或者如果手边有笔记本,或者手机就记录在 WizNote 中,但这样一来很多内容都散布在各个不同的软件或者应用中,以前也整理过 gitbook 但是一直没有那么系统的想要说整理出一本书这样,所以一直依赖还是用这个博客,记录点点滴滴的学习笔记。
GitHub 地址:
开源协议: MIT license
安装依赖条件:
浏览 BookStack 的官网 主页上列举了一些 Feature 都是一些非常贴心的功能。
这一些功能集合到一起就像是整合版本的 GitBook,支持多人编辑,还有权限管理,完美的解决了使用 markdown + git 管理当文件太多的情况下管理的不便。基于这些理由,所以就在我的 NAS 上,用 Docker 搞了一个。目前先自己用着记录一些暂时未整理好,或者暂时不能公开的内容吧。
安装的过程也非常简单了,官网给出的教程非常详细了,请参考官网.
首先开启 QNAP 上的 MySQL 服务,然后给 bookstack 新建一个数据库 bookstack,并且给 bookstack 这个数据单独创建一个用户 bookstack。然后因为我的 Docker 配置的网关地址是 10.0.3.1 所以就写了宿主机的地址。然后就不用上面提到的教程单独给 BookStack 开一个 MySQL 实例了,共享宿主机的 MySQL 就行了。
version: "2"
services:
bookstack:
image: linuxserver/bookstack
container_name: bookstack
environment:
- PUID=1000
- PGID=1000
- DB_HOST=10.0.3.1:3306
- DB_USER=bookstack
- DB_PASS=<password>
- DB_DATABASE=bookstack
volumes:
- /share/Container/bookstack_config:/config
ports:
- 6875:80
restart: unless-stopped
然后等待启动即可。
如果遇到这个问题:
nc: getaddrinfo: Name does not resolve
可以参考 stackoverflow
不以引进正版为理由的打击盗版都是文化审查。
rss
这是我再次开始关注 PT 时,注册的第一个网站。
迄今为止用过的最舒服的 PT 站。
没有考核,速度最快,所以完成后我也会挂很长时间。
作种人数一般
重在亚洲的影视资源。可我还没有账号,求邀请。感谢好心人给我邀请,再次感谢 🙏🏻️.
无账号,求邀请。
听说是挺大的站,求邀请吧
最后如果有很多 PT 站,推荐 PT Plugin Plus 这个浏览器扩展来管理。
Spring AOP 的几个常用的使用场景:
AOP 提供了不同于 OOP 的另一种全新的软件架构思考方式。
Spring 中有两种方式来使用 AOP
一些关键性的术语:
join-point
: a point during the execution of a program, in spring AOP always represents a method executionpointcut
:is a predicate or expression that matches join-pointadvice
: actions taken by aspect at a particular join-point, is associated with a pointcut expression and runs at any join point matched by the pointcutweaving
: linking aspects with other application types or objects to create an advised object.基于上面的认知,知道 join-point 可以认为是方法调用的时刻,所以 Spring 中有 5 种类型的 Advice 时机:
Before advice
, 方法执行前(无法阻止方法执行,除非抛出异常)After returning advice
, 正常方法(无异常)返回后执行After throwing advice
, 抛出异常时执行After advice
, 不管方法正常或者抛出异常后执行Around advice
, 方法调用前后Spring 中 AOP 的实现主要是通过 JDK [[动态代理]]和 cglib 动态代理完成。1
InvocationHandler
和 Proxy
类具体的版本可以自行搜索使用。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
Pointcut expression 由一个 pointcut designator(PCD) 开头,来告诉 Spring 什么时候匹配。Spring 支持很多个 pointcut designators ,最常见的就是 execution 了。
matching method execution join points
匹配某一个特定方法:
@Pointcut("execution(public String info.einverne.FooDao.get(Long))")
假如要匹配 FooDao 中所有方法:
@Pointcut("execution(* info.einverne.FooDao.*(..))")
第一个*
匹配所有的返回值,(..)
表示匹配任意数量的参数。
limits matching to join points within certain types
使用 within 也能够达到上面的效果,将类型限定到 FooDao
@Pointcut("within(info.einverne.springboot.demo.dao.FooDao)")
public void logWithClass(JoinPoint jp) {}
或者匹配某个包下所有
@Pointcut("within(info.einverne.springboot.demo.dao..*)")
public void logWithPackage(JoinPoint jp) {}
this
匹配 bean reference 是给定类型的实例,target
匹配 target Object 是给定类型的实例。this
适用于 Spring AOP 创建 CGLIB-based proxy, target
适用于 JDK-based proxy.
@Pointcut("target(info.einverne.springboot.demo.dao.BaseDao)")
public void logBaseDao(JoinPoint jp) {}
@Pointcut("this(info.einverne.springboot.demo.dao.FooDao)")
public void logThis(JoinPoint jp) {}
limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types
匹配特定方法参数
// 匹配方法参数是 Long 的方法
@Pointcut("args(Long)")
public void argsMatchLong() {}
args 后面加类名,表示入参是该类的方法。
limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type
@Pointcut("@target(org.springframework.stereotype.Repository)")
limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given type(s)
// 匹配所有使用了 SomeCustomAnnotation 注解的参数的方法
@Pointcut("@args(info.einverne.SomeCustomAnnotation)")
public void args() {}
@args
需要接注解的类名,表示方法运行时入参标注了指定的注解。
limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP)
@Pointcut("@within(org.springframework.stereotype.Repository)")
等于:
@Pointcut("within(@org.springframework.stereotype.Repository *)")
@target
和 @within
的区别:Spring AOP 基于 dynamic proxies, 它仅仅提供了 public, non-static 方法执行的 interception. 而使用 CGLIB proxies, 你可以 intercept package-scoped, non-static 方法。然而 AspectJ 甚至可以 intercept 方法的调用(而不仅仅是方法的执行),member field access (静态或者非静态),constructor call/execution, static class initialisation 等等。2
@annotation
可以用来表示被注解引用的时机。
limits matching to join points where the subject of the join point (method being executed in Spring AOP) has the given annotation
比如自定义注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}
那在定义 Pointcut 时可以使用:
@Around("@annotation(com.package.LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {}
可以使用 @Order
来指定先后执行顺序。
execution 在使用时有自己的语法规则:
execution(modifiers-pattern? return-type-pattern declaring-type-pattern?method-name-pattern(param-pattern) throws-pattern?)
public/private void/String/... com.xxxx.SomeClass .saveUser throws *Exception
带问号的可以省略,其他可以支持正则。
所有的 Pointcut 之间都可以使用 &&
,||
, !
来连接。
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
@Pointcut("within(com.xyz.someapp.trading..*)")
private void inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}
代码地址:https://github.com/einverne/thrift-swift-demo/tree/master/spring-boot-demo
wget https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
sudo chmod +x wp-cli.phar
sudo ln -s /var/www/www.einverne.info/html/wp-cli.phar /usr/local/bin/wp
wp --info
To run any command with WP CLI, you must be in the public directory of your WordPress instance installed.
Check version
wp core version
Check update
wp core check-update
Update
sudo -u www-data wp core update
sudo -u www-data wp core update-db
Check plugins
wp plugin list
sudo -u www-data wp plugin deactivate wordpress-seo
sudo -u www-data wp plugin uninstall wordpress-seo
sudo -u www-data wp plugin update --all
wp theme search twentyfourteen
sudo -u www-data wp theme install twentyfourteen
sudo -u www-data wp theme activate twentyfourteen
sudo -u www-data wp theme update twentyfourteen
sudo -u www-data wp theme update --all
wp theme list
sudo -u www-data wp theme activate twentyseventeen
sudo -u www-data wp theme uninstall twentyfourteen
wp post list
wp post create --post_type=post --post_title='A sample post'
wp post update 123 --post_status=draft
wp post delete 123
前两天鼻炎又犯了,去过很多次医院,也去过不同的医院,有说是慢性鼻炎,有说是过敏性鼻炎,这次检查说是鼻窦炎,总之就是鼻炎了。也尝试过各种药,各种滴鼻液,各种喷雾剂,各种洗鼻水,总是能缓解一段时间,然后到秋冬季节就又会差很多。也不知道是不是环境导致,毕竟大学毕业后还没有在不同城市生活过。所以上一次去了医院之后就在想,对于有些病,或者有些病理信息,是不是我可以在互联网上获得一些信息,然后自我调理,而这两天正好看到 Twitter 上有人提起,所以就整理一下。
专业的医学或健康知识可信获取信息源:
美国疾病控制与预防中心 https://www.cdc.gov/ 世界各国的 CDC https://en.wikipedia.org/wiki/CDC
美国国立卫生研究院 https://www.nih.gov/
糖尿病 https://dtc.ucsf.edu/zh-hans/
改造网站支持 Progressive Web Apps (PWA),改善移动端体验。
主要分成一下几步:
检测当前的浏览器是否支持 Service Worker
调试 Service Worker,可以在 Chrome 开发者选项 Application 看到 Service Worker.
创建 sw.js
并注册
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/sw.js');
//navigator.serviceWorker.ready always resolve
navigator.serviceWorker.ready.then(function (registration) {
console.log('Service worker successfully registered on scope', registration.scope);
});
});
}
</script>
关于 sw.js 比较复杂, 可以参考文末 Google 的文档。
manifest 属性
页面中添加 manifest.json 使之生效。
<link rel="manifest" href="/manifest.json">
这里 可以生成 manifest 和不同尺寸的 icon
部署后可以测试一下
整理文件的时候总想快速的删掉重复的文件,这里就总结下个人使用感觉良好的几个命令工具,包括 jdupes, rdfind, fdupes 这些。
开源地址:
fdupes 的增强版,根据作者自己的描述,jdupes 比 fdupes 1.51 版本要快 7 倍左右。
使用方式:
Usage: jdupes [options] DIRECTORY...
和 fdupes 类似, jdupes 也有类似的选项:
-d --delete prompt user for files to preserve and delete all
others; important: under particular circumstances,
data may be lost when using this option together
with -s or --symlinks, or when specifying a
particular directory more than once; refer to the
documentation for additional information
-N --noprompt together with --delete, preserve the first file in
each set of duplicates and delete the rest without
prompting the user
-r --recurse for every directory, process its subdirectories too
所以总结一下:
jdupes -r path/to/dir
这行命令不会真正去删重复的文件,如果要删除,用 -d
参数:
jdupes -dr path/to/dir
此时 jdupes 会打印出报告,然后一个一个让用户自己去确认要删除哪一个。
安装使用:
sudo apt-get install rdfind
rdfind -dryrun true path/to/dir
结果会保存在 results.txt 文件中。如果要真正删除 (Be Carefule):
rdfind -deleteduplicates true path/to/dir
或者建立硬链接
rdfind -makehardlinks true path/to/dir
安装使用:
sudo apt install fdupes
fdupes path/to/dir
递归搜索:
fdupes -r path/to/dir
如果要删除重复内容可以使用 -d
选项(同样需要非常谨慎):
fdupes -d path/to/dir
-d
选项会弹出选择,用户可以手动选择保留的文件。如果使用 -I
选项会在遇到重复文件时直接删除。
-N
选项和 --delete
一起使用时,会保留第一个文件,然后删除之后的重复文件,不会弹出让用户确认。
最强悍模式:
fdupes -rdN path/to/dir
在 review tldr 的 PR 时又看到了一个 C 语言实现的 duperemove,作者没有提供 benchmark,有机会可以尝试一下。
这篇文章受到 Intellij 官方插件 IDE Features Trainer 的启发,学习一个编辑器应该归类,从不同的操作学习。从基本的编辑,到代码导航,再到辅助,到重构,重要的不是学习这些快捷键,而是学习可以怎么样做,并且用这样的思考方式用到不同的编辑器中。
Mac 上常见的四个快捷键对应关系,简单的可以将 Alt 对应 Mac 下的 Option,而在 Mac 下 Cmd 和 Ctrl 被人为的分隔开来,Cmd 大多数与GUI相关,Cmd+Q退出应用,Cmd+W关闭一个Tab,而Ctrl和终端相关,Ctrl+a则是跳转到行首,Ctrl+e跳转到行尾。然后和Shift,Option结合就能组合成非常多常用的功能。Windows下不足的一个地方就是将 Win 键的功能单一化了,大部分的情况下Win 键是鸡肋。
另外 Shift 可以认为是一个相反的操作,比如 Cmd+Tab 是切换应用,那么 Cmd+Shift+Tab 就是反向切换应用。再比如在 IntelliJ IDEA 中 Cmd+z 是 undo,那么 Cmd+Shift+z 就是 redo,撤销之前的撤销。
一个编辑器基本的操作,包括复制,剪切,粘贴,选择,多点选择,折叠代码块等等。而关于复制,剪切,粘贴 IdeaVim 已经完全满足需求,不需要用 Intellij 内置的任何命令。
选择,块选择,本来 Vim 的选择模式也已经足够强大,不过 Intellij 提供了如下两个方式相较于 Vim 的块选稍微强大一些。
原来 Vim 的块选,比如想要选择某一个方法,大致可以使用 vap
,或者选择花括号内容 vi{
等等,在非常清楚需求的情况下非常方便,但是比如有些时候不想选择整个段落,想要可视化的选择一些代码块,不妨试试上面两个快捷键。
折叠与展开,倒是不复杂。
Ctrl -/+ Collapse/Expand a code region Ctrl Shift -/+ Collapse/Expand all regions in a file
多选,比较常见地一种场景就是变量重命名,当然有些时候比如编辑 html 时批量替换某些标签,有很多方法可以实现,比如变量重命名功能,或者批量替换,又或者使用 vim 的 dot 命令。
Intellij 当然也提供了很多方式,上面提到的只是其中的一种。
生成一些模板方法,默认的快捷键是 Cmd+n, 自动生成构造方法,toString 方法,getset 方法,或者 override 方法等等。
批量重命名,很有用的快捷键,必须知道。
Ctrl + Alt + V
个人对方法提取用的还是比较多的,重构代码或者重新规划代码时非常有用。
格式化,对于格式化的要求应该在任何保存的时候进行格式化,应该在提交代码前强制进行格式化。当然用快捷键时不时的格式化一下也可以。
显示参数
Vim 插件已经能够做到非常好的在单文件内浏览了,无论是上下,或者翻页,或者查询特定变量,方法。如果要做到查询方法的父类或者接口就不得不借助 Intellij 自身的快捷键。
在阅读代码时有几个操作经常会用到:
个人使用 Vim 的 *
和 np
基本满足了查询当前字符串的需求,所以这里也就不列举 IDE 自带的快捷键了。
全局搜索,默认的快捷键是 Shift + Shift, 这是一个非常有用的快捷键,可以搜索 IntelliJ IDEA 内部的功能,同时也可以模糊搜索项目代码文件,执行任务,跳转等等。
默认的快捷键是 Alt+Enter
默认的快捷键是 Alt(Option)+F12
重构代码,会弹出一个功能选单 Refactor this,在这个功能选单中可以做如下事情。
停留在变量上,方法名,类名上:
Cmd 系列
快捷键 | 功能描述 |
---|---|
Cmd+q | Q退出应用 |
Cmd+c/v/x | copy/paste/cut |
Cmd+z | |
Cmd+w | close Tab |
Cmd+e | recent file |
Cmd+n | generate |
Cmd+o | file structure |
Ctrl 系列
快捷键 | 功能描述 |
---|---|
Ctrl+a/e | 行首行尾 |
Ctrl+n/p | next line/Previous line |
Ctrl+b | go to super class |
Ctrl+g | find usage |
Ctrl+h | find in path |
Ctrl+Option+b | go to implements |
Linux Mint 自带的备份和还原工具就是 timeshift, 今天看到有人贡献 timeshift 的命令行版本,突然意识到这个工具其实还有命令行版本。
sudo apt-add-repository -y ppa:teejee2008/ppa
sudo apt-get update
sudo apt-get install timeshift
timeshift 提供两种模式的备份方式:
RSYNC 在第一次使用时会拷贝所有文件,以后每次备份都是增量备份,使用硬链接创建从上一次快照未修改的系统文件。快照文件可以保存到任何 Linux 文件系统的硬盘格式下,保存快照到非系统盘或者外部硬盘上,这样即使系统盘损坏或者被格式化也能够快速从外部硬盘恢复数据。RSYNC 支持排除文件和目录来节省硬盘空间。
BTRFS 需要安装 btrfs-tools
,快照通过 BTRFS 文件系统创建,快照备份和恢复的速度要比 RSYNC 快,快照创建和恢复都是原子事务的,不能中断。快照通过替换系统 subvolumns 来恢复,因为文件没有拷贝,删除或者覆盖,不会有文件丢失的风险。恢复后的系统会作为一次新的快照。快照在备份时是完美地逐字节拷贝,不能排除任何文件。快照会存在系统相同的硬盘上,暂时还不支持备份到其他硬盘,如果系统盘损坏,那么快照也会丢失。初始 BTRFS 备份是 0 字节,但是随着系统使用占用内容会逐日增多,快照中的文件依然还是会指向原始的文件 block. 系统必须安装在 BTRFS 分区上,并使用 Ubuntu-type subvolumn layout(@ and @home subvolumns),其他的 layouts 不支持。
通过界面可以非常快速的设置 timeshift.
在标签页,Filters 一栏中可以设置不备份的路径。
通过界面可以定制简单的定时备份任务,但是如果界面无法满足高级的需求,比如固定时间调用 timeshift 来备份,那么可以使用 cron 脚本来定时备份。比如要在每天下午 7 点中执行备份,可以新建 /etc/cron.d/timeshift_daily_7p
并在其中配置:
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=""
0 19 * * * root timeshift --create --tags D --scripted
如果安装某些程序导致了无法进入系统,那么可以用 USB 上的系统进入,然后在 USB 启动的系统中使用 timeshift 来恢复系统。