LoginSignup
7
8

More than 5 years have passed since last update.

zshの起動が重くなったので改善する

Last updated at Posted at 2017-06-01

久しぶりにzshの環境をいじったら起動が重くなったので改善したメモ。

これらの対策+なんでもzcompileでtime zsh -i -c exitが0.7秒から0.17秒になりなんとか許容できるぐらいになった。

brew file wrapper

マニュアルには.zshrcに

if [ -f $(brew --prefix)/etc/brew-wrap ];then
  source $(brew --prefix)/etc/brew-wrap
fi

と書けとあるんでそのままコピペしたけど、実はbrew --prefixは結構時間がかかる。そんなに変わるものでもないので/usr/local決め打ちに書き直した。

zplug

プロファイラーで調べて簡単に直せそうなところからいじってみた。

compinit

compinitが結構時間かかるんだけど、よく調べたら.zplug/base/core/core.zshと.zplug/base/core/load.zshの2回呼ばれていて(他にgoogle cloud sdkでもさらに1回ともともと自分の.zshrcの中にあったもう1回の計4回)、なんとなく無駄っぽいから後に呼ばれるload.zshの方のはコメントアウトして見た。何か理由があるのかもしれないけど自分については特に補完がおかしくなるわけでもないのでOKということにしておく。 $fpathの設定を行うプラグインがあることを考慮するとcore.zshの方はタイミングが早すぎると思われるのでコメントアウトして様子見。

__zplug::job::handle::flock

flockして混ざらないようにファイルに書く関数があって、ログを書くたびに呼ばれているのだけど、flockがサブシェルを使う書き方になっていた。プロセス終了でロックが自動的に解放されるから解放忘れを気にしなくていい便利な書き方なんだけど、何回も呼ばれるとプロセス生成のオーバーヘッドが積み重なってそれなりの量になる。

.zplug/base/job/handle.zsh
    (
    until zsystem flock -t 3 "$file"
    do
        # 略
    done

    # 略
    )

以下のようにサブシェルを使わないように書き換え。

.zplug/base/job/handle.zsh
    until zsystem flock -t 3 -f fd "$file"
    do
        # 略
    done

    # 略
    zsystem flock -u $fd

__zplug::log::capture::error

プラグインを読み込むところでエラー出力をログに書くために以下のようなことをしています。

.zplug/base/core/sources.zsh
        {
            # Directory '/base/sources' needs to be included in FPATH
            autoload -Uz "$val.zsh"
            eval "$val.zsh"
            unfunction "$val.zsh"
        } \
            2> >(__zplug::log::capture::error) >/dev/null

パイプを使っているのでプロセス生成のオーバーヘッドがあります。ちゃんとした修正方法は思いついてないのですが、これが必要になるのは不具合があったときで普段は何も出力されない筈なので、自分は起動速度を取ってログ出力部分は削除しました。

__zplug::"io"::file::rm_touch

rm_touchというのが結構上位に来ていて中を見たらこんな感じだった。

.zplug/base/io/file.zsh
__zplug::io::file::rm_touch()
{
    local filepath="${argv:?}"

    # For shorten the calculation time
    if [[ ! -d ${filepath:h} ]]; then
        mkdir -p "${filepath:h}"
    fi

    rm -f "$filepath"
    touch "$filepath"
}

rmとtouchは外部コマンドで毎回呼ばれるので時間がかかっていると思われる。しかし、これは結局"$filepath"という空のファイルができればいいだけのような気がするので、以下のように書き換え。

.zplug/base/io/file.zsh
__zplug::io::file::rm_touch()
{
    local filepath="${argv:?}"

    # For shorten the calculation time
    if [[ ! -d ${filepath:h} ]]; then
        mkdir -p "${filepath:h}"
    fi

    : > "$filepath"
}

zplug check

マニュアルには.zshrcに以下のように記述して未インストールのプラグインがあるときはインストールするか聞くようにするといいとあるのだけれど、zplug checkも結構時間がかかります。

.zshrc
    if ! zplug check --verbose; then
        printf "Install? [y/N]: "
        if read -q; then
            echo; zplug install
        fi
    fi

読み込むべきプラグインが増えるのは.zshrcに変化があったときと考えていいと思うので、チェック時刻を保存して.zshrcが新しくなっているときだけこれをするようにしました。

.zshrc
if [ ! ~/.zplug/last_zshrc_check_time -nt ~/.zshrc ]; then
    touch ~/.zplug/last_zshrc_check_time
    if ! zplug check --verbose; then
        printf "Install? [y/N]: "
        if read -q; then
            echo; zplug install
        fi
    fi
fi

google-cloud-sdkのcompletion.zsh.inc

zplugのとこでも軽く触れたけどこいつの中でもcompinitしていて無駄だからコメントアウト。

7
8
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8