to be
a problem slover

zsh启动速度优化 – 5倍提升

Shiming阅读(6294)

概述

Mac 下 iterm + zsh + ohmyzsh配置的组合本来很好用,但是随着使用插件的增多,再加上.zshrc / .zprofile文件中的一些命令加载耗时,现在新开一个 zsh tab 页异常的慢(3s 以上)。我平时使用命令行的频率很高,所以我决心做一次 zsh 启动性能优化。

优化的结果是3s启动时间变成0.6s,下面是详细的步骤。

环境

软件

zsh 5.7.1 (x86_64-apple-darwin19.0)

ohmyzsh commit id 7525b1d533b927bc40e3cfb29e399e5f2e0828d4

iterm2 3.3.11

启用的插件

plugins=(
  git
  z
  jsontools
  vi-mode
  docker
  docker-compose
  kubectl
  command-not-found
  sudo
  zsh-brew-services
  zsh_reload
  zsh-completions
  zsh-syntax-highlighting
#  zsh-autosuggestions
  extract
)

nvm 配置

    export NVM_DIR="$HOME/.nvm"
    [ -s "/usr/local/opt/nvm/nvm.sh" ] && . "/usr/local/opt/nvm/nvm.sh"  # This loads nvm
    [ -s "/usr/local/opt/nvm/etc/bash_completion" ] && . "/usr/local/opt/nvm/etc/bash_completion"  # This loads nvm bash_completion

查看启动时间

执行\time zsh -i -c exit命令可以查看 zsh 启动时间。

$ \time zsh -i -c exit
        3.09 real         1.36 user         1.17 sys

作为对比,使用--no-rcs 选项可以测试不加载 .zshrc 文件的启动时间,只要 0.01 秒。

time zsh --no-rcs -i -c exit
        0.01 real         0.00 user         0.00 sys

所以优化的重点是 .zshrc 文件。

时间消耗分析

量化时间消耗才能有的放矢。

.zshrc 首行插入 zmodload zsh/zprof,依次执行以下命令:

$ source ~/.zshrc
$ zsh
$ zprof

可以得到类似以下结果,耗时都按顺序排好了:

num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    1         299.61   299.61   18.92%    299.53   299.53   18.91%  nvm_die_on_prefix
 2)    2         733.99   366.99   46.35%    260.46   130.23   16.45%  nvm
 3)    1         184.36   184.36   11.64%    184.36   184.36   11.64%  compdump
 4)    1         173.62   173.62   10.96%    161.51   161.51   10.20%  nvm_ensure_version_installed
 5)    1         879.20   879.20   55.52%    145.21   145.21    9.17%  nvm_auto
 6)    2         139.50    69.75    8.81%    137.46    68.73    8.68%  bracketed-paste-magic
 7)    1         383.49   383.49   24.22%     94.65    94.65    5.98%  compinit
 8)    1          93.53    93.53    5.91%     93.27    93.27    5.89%  __kubectl_bash_source
 9)  783          80.83     0.10    5.10%     80.83     0.10    5.10%  compdef
10)    3          53.95    17.98    3.41%     53.95    17.98    3.41%  compaudit
11)    1          17.78    17.78    1.12%     17.78    17.78    1.12%  nvm_supports_source_options
12)    1          12.11    12.11    0.76%     12.11    12.11    0.76%  nvm_is_version_installed
13)    1          11.21    11.21    0.71%     10.71    10.71    0.68%  _zsh_highlight_load_highlighters
14)    1           5.93     5.93    0.37%      5.93     5.93    0.37%  _zsh_highlight_bind_widgets
15)    2           5.93     2.96    0.37%      5.93     2.96    0.37%  grep-flag-available
16)    2           5.69     2.85    0.36%      5.69     2.85    0.36%  env_default
17)    1           2.61     2.61    0.16%      2.61     2.61    0.16%  iterm2_decorate_prompt
18)    4           3.58     0.90    0.23%      1.88     0.47    0.12%  _zsh_highlight
19)    6           1.52     0.25    0.10%      1.52     0.25    0.10%  url-quote-magic
20)    1           1.31     1.31    0.08%      1.31     1.31    0.08%  _z_precmd
21)    1           1.01     1.01    0.06%      1.01     1.01    0.06%  colors
22)   25           0.70     0.03    0.04%      0.70     0.03    0.04%  is_plugin
23)    2           0.95     0.48    0.06%      0.61     0.30    0.04%  _zsh_highlight_main_highlighter_highlight_list
24)    2           0.60     0.30    0.04%      0.60     0.30    0.04%  add-zsh-hook
25)    3           0.57     0.19    0.04%      0.57     0.19    0.04%  is-at-least
26)   11           2.07     0.19    0.13%      0.50     0.05    0.03%  (anon)
27)    2           0.37     0.18    0.02%      0.37     0.18    0.02%  nvm_has
28)    2           1.55     0.78    0.10%      0.33     0.16    0.02%  _zsh_highlight_highlighter_main_paint
29)    4         143.48    35.87    9.06%      0.31     0.08    0.02%  _zsh_highlight_call_widget
30)    2           0.19     0.09    0.01%      0.19     0.09    0.01%  _zsh_highlight_main_calculate_fallback
31)    1           0.26     0.26    0.02%      0.17     0.17    0.01%  complete
32)    4           0.16     0.04    0.01%      0.16     0.04    0.01%  _zsh_highlight_main__type
33)    2           0.13     0.06    0.01%      0.13     0.06    0.01%  title
34)    2           0.12     0.06    0.01%      0.10     0.05    0.01%  iterm2_print_state_data
35)    1           0.14     0.14    0.01%      0.09     0.09    0.01%  omz_termsupport_preexec
36)    2           0.09     0.04    0.01%      0.09     0.04    0.01%  _zsh_highlight_add_highlight
37)    1           0.08     0.08    0.01%      0.08     0.08    0.01%  _zsh_highlight_main__precmd_hook
38)    2           0.08     0.04    0.01%      0.08     0.04    0.01%  _zsh_highlight_main_highlighter__try_expand_parameter
39)    1         897.05   897.05   56.64%      0.07     0.07    0.00%  nvm_process_parameters
40)    1           0.07     0.07    0.00%      0.07     0.07    0.00%  zle-line-init
41)    1           2.74     2.74    0.17%      0.07     0.07    0.00%  iterm2_precmd
42)    1         141.08   141.08    8.91%      0.07     0.07    0.00%  _zsh_highlight_widget_orig-s0.0000030000-r5757-bracketed-paste
43)    4           0.11     0.03    0.01%      0.07     0.02    0.00%  _zsh_highlight_highlighter_main_predicate
44)    1           0.05     0.05    0.00%      0.05     0.05    0.00%  bashcompinit
45)    1           0.81     0.81    0.05%      0.05     0.05    0.00%  _zsh_highlight_widget_orig-s0.0000030000-r5757-zle-line-init
46)    3           0.05     0.02    0.00%      0.05     0.02    0.00%  _zsh_highlight_buffer_modified
47)    2           0.05     0.02    0.00%      0.05     0.02    0.00%  _zsh_highlight_main_add_region_highlight
48)    2           0.04     0.02    0.00%      0.04     0.02    0.00%  _zsh_highlight_main_highlighter_expand_path
49)    1           0.12     0.12    0.01%      0.04     0.04    0.00%  omz_termsupport_precmd
50)    1           0.03     0.03    0.00%      0.03     0.03    0.00%  pasteinit
51)    1           1.30     1.30    0.08%      0.03     0.03    0.00%  _zsh_highlight_widget_orig-s0.0000030000-r5757-zle-line-finish
52)    1           0.48     0.48    0.03%      0.03     0.03    0.00%  _zsh_highlight_widget_orig-s0.0000030000-r5757-accept-line
53)    1           0.07     0.07    0.00%      0.03     0.03    0.00%  iterm2_after_cmd_executes
54)    1           0.02     0.02    0.00%      0.02     0.02    0.00%  zle-line-finish
55)    2           0.02     0.01    0.00%      0.02     0.01    0.00%  iterm2_print_user_vars
56)    1           0.03     0.03    0.00%      0.02     0.02    0.00%  iterm2_preexec
57)    1           0.02     0.02    0.00%      0.02     0.02    0.00%  nvm_is_zsh
58)    2           0.01     0.01    0.00%      0.01     0.01    0.00%  _zsh_highlight_main__is_redirection
59)    1           0.01     0.01    0.00%      0.01     0.01    0.00%  _zsh_highlight_preexec_hook
60)    1           0.01     0.01    0.00%      0.01     0.01    0.00%  iterm2_before_cmd_executes
61)    1           0.01     0.01    0.00%      0.01     0.01    0.00%  pastefinish

问题解决

通过分析可以看出 nvm 命令的加载非常耗时,80% 的精力解决这 20% 的问题就够了。

一通搜索后得知加速 nvm 的加载主要有两种办法:

  • 懒加载,使用 node 命令的时候才加载 nvm
lazy_load_nvm() {
  unset -f node
  export NVM_DIR=~/.nvm
  [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh"
}

node() {
  lazy_load_nvm
  node $@
}
  • 使用默认 node 版本 + –no-use 选项
    # Add default node to path
    export PATH=$HOME/.nvm/versions/node/v10.22.0/bin:$PATH

    # load nvm
    export NVM_DIR="$HOME/.nvm"
    [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh" --no-use

我使用的第二种方案,瞬间 zsh 启动速度提高了 1.2 秒左右,而且 node、nvm 命令都还能正常使用!打开新 terminal tab 页感受已经好很多。

其他优化

我继续使用zprof分析启动时间,再去掉了几个插件,最终剩下的插件如下:

plugins=(
  git
  z
  jsontools
  vi-mode
  docker
  docker-compose
  sudo
  zsh-brew-services
  zsh_reload
  zsh-syntax-highlighting
)

现在 terminal 上打开新 tab 的时间为 0.6s,相比之前的 3s 已经很满意了。

$ \time zsh -i -c exit
        0.61 real         0.32 user         0.26 sys

优化记录

因为我在 github 用 .dotfiles 管理配置文件,所以本次优化都留有记录,有兴趣可以去查看。

https://github.com/huahuayu/.dotfile/commit/31d9cc2452f8a29e1566b0edb8596772a5756790

参考资料

How to speed up shell load while using NVM

简单配置让iterm2用得更爽

Shiming阅读(5312)

概述

iterm2比 mac 原生的 terminal 好用很多,是 mac 下必装的软件之一,装好后简单配置就用的很爽了。我个人的配置主要有以下方面,供参考:

  • 开机默认启动 iterm
  • 主题设置为 Solarized Dark
  • 设置更美观的中文字体
  • 开启全局快捷键opton + space方便随时唤起iterm2
  • 设置 vim 中鼠标选中复制功能
  • 设置 vim 支持鼠标滚动
  • 新 tab 页使用前一个 tab 页的目录
  • 备份配置文件

版本信息

macOS
10.15.2

iterm2
3.3.7

开机默认启动

System Preferences > Users & Groups > Login Items > 点加号 > Applications列表选中iTerm

主题设置

Preferences > Profiles > Colors > Color Presets > 选择Solarized Dark

之所以选择这个颜色,因为这个颜色(姑且称为哑光淡蓝色吧),在很多支持配色的软件里都有,是一个经典配色了,而且我 vscode 也是这个颜色

字体设置

Preferens > Profiles > Text > 勾上Use a different font for non-ASCII text > 选择自己喜欢的字体

iterm 的默认字体是 Monaco,Monaco 的中文本来也还行,但是如果将字体放大一点,会发现英文字体变大了,但是中文看起来比英文还小。

好在 iterm 支持为非 ASCII 的字符设置另一种字体,所以我选择了 Helvetica Neue(和 Mac 下印象笔记的字体一致,相信他们的专业审美),看起来好多了。

实际效果:

全局唤醒快捷键

Preferences > Keys > Hotkey > 勾上Show/hide all windows with a system-wide hotkey
默认快捷键是option + space,用起来很顺手,在任何界面需要敲命令行,按一下唤出,再按一下隐藏,非常方便。

vim 中鼠标选中复制

默认 iterm2 是开启mouse reporting功能的,不把它关闭鼠标选中 vim 中的文本,按command + c键是不能复制的(而是会进入 vim 的 visual 模式!)。我查了很久才在 iterm2 的官方 gitlab 库中搜到一个issue说到这个解决方案。网上基本上没有说法。

Preferens > Profiles > Terminal > 关闭Enable mouse reporting

设置 vim 支持鼠标滚动

关闭mouse reporting后,vim 编辑时就不支持鼠标滚动了,但是 iterm2 可以设置通过发送 j/k 键来支持滚动,preferences > advance > 搜索mouse > scroll whell down 那里写\j > scroll whell up那里写\k

设置无限向上滚动

有时候 terminal 上输出的内容很多,需要向上滚动查看输出历史,建议设置无限滚动 preferences > Profiles > Terminal > Unlimited scrollback

新 tab 页目录设置

如果不设置,默认新打开一个 tab 页面或者分屏时,新的窗口的进入的目录为用户家目录。可以设置为沿用上一个 tab 页的当前目录 preferences > profiles > general > reuse previous session's directory

备份配置

自己的配置最好备份好,下次有需要再导入即可,体验保持一致。
Preferences > Profiles > Other Actions > Save All Profiles as JSON...

导出的配置文件可以放到 dotfiles 上传到 github 保存(但如果保存了密码之类的配置就不要上传了),换电脑的时候再也不用担心软件用不顺手了。

结论

  • 通过简单配置,iterm2 变得更美观易用,对中文支持也更好。
  • 将配置保存到 dotfiles,使用 github 管理有助于在任何机器上保持一致的体验。

解决vim选中文字不能复制的问题

Shiming阅读(4434)

概述

最近发现在iterm2中打开vim,用鼠标选中文字,并用command + c复制选中的文字,但粘贴出来是空的。查了一圈终于在iterm2的官方gitlab issue库里发现了解决办法。将Enable mouse reporting这个设置去掉即可。

版本信息

操作系统
Mac os 10.15.2

iterm2
iterm2 3.3.6
iterm2 3.3.7

vim
Vi IMproved 8.1 (2018 May 18, compiled Dec 26 2018 02:33:06)

重现步骤

  1. iterm2中使用cat命令打印文件,然后用鼠标选中command + c可以正常复制。
  2. 但是用vim打开文件,选中文字用command + c复制,却不能复制。
  3. 并且当鼠标点击vim中的文字后,vim会自动变为visual模式。

解决方案

iterm2 > Preferences > Profiles > Terminal > Enable mouse reporting 去掉勾选

mouse reporting

mouse reporting的作用是在vim编辑时识别鼠标,可以支持鼠标滚轮查看文件内容(需要在.vimrc中加入设置支持鼠标set mouse=a)。关闭了mouse reporting后就不支持鼠标滚轮了。

那要使用鼠标滚轮怎么办?

可在iterm2 > preferences > advance > 搜索mouse > scroll whell down 那里写\j > scroll whell up那里写\k,作用就是发送j/k键到vim实现滚动效果。

更多信息

Mac自带的terminal也会有这个问题,在View > Allow Mouse Reporting 去掉勾选即可