今回の結果:速度はzstd、合成ログの最小サイズはxz -6

16 MiBの合成ログでは、xz -6が今回の4設定で最小になりました。一方、zstd -3は圧縮・展開とも短時間で完了しました。gzip済みデータと疑似乱数データでは、どの設定もサイズ削減の効果はごく小さいか、かえって増えました。

この結果からは、頻繁に作成・展開するログのアーカイブにはzstd、処理時間を使って保管サイズを減らしたい場合にはxzを試す、という選び方が考えられます。ただし、単一環境・小規模な生成データでの結果です。実際のソースコード、VMイメージ、バックアップ全体でも同じ差になるとは限りません。

測定環境と比較条件

項目条件
測定日2026年10月26日(日本時間)
CPUIntel Core i7-10750H @ 2.60 GHz(6コア・12スレッド)
OSFedora Linux 44、Linux 7.2.9-201.fc44.x86_64
ツールXZ Utils 5.8.2、zstd 1.5.7、Python 3.14.8
圧縮設定xz:-T1 -3と-T1 -6、zstd:--single-thread -3と--single-thread -9
繰り返し各データ・設定で圧縮と展開を1回予備実行し、その後3回測定。時間とピークRSSはそれぞれの中央値
計時Pythonのperf_counter_nsでプロセス起動から終了までを計測。GNU timeの起動とファイルI/Oを含む
メモリGNU timeの%Mで圧縮・展開プロセスのピークRSSを取得。計測用PythonやOSキャッシュのメモリは含まない
キャッシュ・出力先キャッシュ消去なし。圧縮は一時ファイルへ出力、展開は/dev/nullへ出力。fsyncは実行していない

圧縮レベルの数字はツールごとの尺度です。xzの3とzstdの3が同じ圧縮強度を意味するわけではありません。圧縮はワーカー数を制限し、全コアを使う設定は今回測定していません。測定順序は各ラウンドでずらしましたが、CPU周波数・他の処理・温度は固定していません。

実データを持ち出さず、3種類のデータを生成

乱数シードは20261026です。すべてテスト用に生成し、個人情報や実サービスのログは使用していません。疑似乱数は暗号学的な乱数ではありません。生成内容とSHA-256は測定結果JSONで確認できます。

今回は同じ単一ファイルを圧縮する処理を比較しています。tarで多数のファイルを収集する時間や、ディスクへ展開ファイルを書き出す時間は含まれません。

圧縮後サイズ・処理時間・メモリの実測結果

残存率は「圧縮後バイト数 ÷ 元のバイト数 × 100」です。低いほど小さく、100%を超えると元より増えています。時間とRSSも小さい方が負担を抑えられます。MiBは1,048,576バイトです。

合成ログ(元サイズ16,777,216バイト)

設定圧縮後(バイト)残存率圧縮(秒)展開(秒)圧縮RSS(MiB)展開RSS(MiB)
xz-32,757,19216.434%1.7990.09229.96.2
xz-62,197,48813.098%5.8970.10084.910.2
zstd-32,872,11817.119%0.0680.0176.66.1
zstd-92,710,75216.157%0.2760.01718.18.1

疑似乱数(元サイズ8,388,608バイト)

設定圧縮後(バイト)残存率圧縮(秒)展開(秒)圧縮RSS(MiB)展開RSS(MiB)
xz-38,389,088100.006%2.3370.00533.16.3
xz-68,389,088100.006%2.2510.00790.710.2
zstd-38,388,814100.002%0.0080.0057.15.9
zstd-98,388,814100.002%0.0170.00618.07.9

gzip済みログ(元サイズ2,760,680バイト)

設定圧縮後(バイト)残存率圧縮(秒)展開(秒)圧縮RSS(MiB)展開RSS(MiB)
xz-32,760,712100.001%0.5470.00623.84.9
xz-62,760,00499.976%0.6030.01342.44.9
zstd-32,760,760100.003%0.0070.0046.95.9
zstd-92,760,759100.003%0.0120.00416.96.3

表の時間はプロセス起動を含むため、数ミリ秒の差は起動処理や測定時の負荷に左右されます。小さな差から細かな性能順位を決める用途には向きません。メモリは各回のピークRSSを集計した中央値であり、必要メモリの上限や全環境の動作保証ではありません。

結果から、どちらを選ぶか

頻繁に作る・何度も展開するなら、まずzstdを試す

合成ログではzstd -3が短い時間で処理できました。zstd -9はさらに小さくできますが、圧縮時間とメモリが増えています。定期的なログ保存や作業用アーカイブでは、まずレベル3で必要なサイズ削減が得られるか確認する方法があります。

保管サイズを優先するなら、xzも実データで比較する

合成ログのxz -6はzstd -3より小さくなりましたが、圧縮時間とピークRSSは大きくなりました。作成頻度が低い配布物や保管用データでは、この追加コストが見合うか判断します。xzの最高レベルやzstdの全レベルを調べた結果ではないため、方式そのものの圧縮率の限界は比較できません。

gzip済みファイルなどは、再圧縮の効果を先に確認する

今回のgzip済みログはxzレベル6でわずかに縮みましたが、処理時間に対して削減量は小さい結果でした。ZIPや動画なども一律に縮まるとは考えず、一部を試してから全量を処理します。

手元のファイルで比較するコマンド

次はGNU timeが/usr/bin/timeにあるLinux環境の例です。sample.logを手元の代表データに置き換えてください。初めて使う出力名を指定し、同名ファイルを上書きしないようにします。

# 元データを残して圧縮。%eは経過秒、%MはピークRSS(KiB)
/usr/bin/time -f 'elapsed_s=%e peak_rss_kib=%M' xz -T1 -6 -c sample.log > sample.log.xz
/usr/bin/time -f 'elapsed_s=%e peak_rss_kib=%M' zstd --single-thread -3 -c sample.log > sample.log.zst

# 展開して読み捨てる場合の時間とメモリ
/usr/bin/time -f 'elapsed_s=%e peak_rss_kib=%M' xz -d -c sample.log.xz > /dev/null
/usr/bin/time -f 'elapsed_s=%e peak_rss_kib=%M' zstd -d -c sample.log.zst > /dev/null

# 圧縮後の正確なバイト数
wc -c sample.log sample.log.xz sample.log.zst

この簡易例のGNU timeは秒を小数2桁で表示するため、短時間処理の精密比較には向きません。記事の表は後述のスクリプトで計測しています。どちらもストレージへの永続化完了までの性能を測るものではありません。

展開した内容が元と一致するかを確認する

# Bashの例:パイプ途中の失敗も終了ステータスへ反映
set -o pipefail
sha256sum sample.log
xz -d -c sample.log.xz | sha256sum
zstd -d -c sample.log.zst | sha256sum

3つのSHA-256値が一致することを確認します。今回の測定でも、12条件すべてで展開後のSHA-256が元データと一致することを確認しました。

生データと再実行用スクリプト

LinuxでPython、xz、zstd、GNU timeを用意し、ダウンロードしたスクリプトのある場所で実行します。一時データは一時ディレクトリに作成し、既存のユーザーデータは読み込みません。データ生成とツールのバージョンによって出力が変わる場合があります。

python3 benchmark-xz-zstd.py --output result.json

結果は実行した環境のものになります。異なるPCや大容量データでは差が変わるため、最終的には自分の用途に近いデータで選んでください。

参考資料

著者について

intrajp。Linux、クラウドインフラ、Kubernetesなどの技術情報を発信しています。この比較では、生成データと設定を明記し、サイズだけでなく処理時間とメモリを判断材料にしています。

運営者情報と記事の方針を見る