grep: メモリが使い果たされました。

grep: メモリが使い果たされました。

私は非常に簡単な検索をしています。

grep -R Milledgeville ~/Documents

しばらくすると、次のエラーが表示されました。

grep: memory exhausted

これをどのように避けることができますか?

私のシステムには10GBのRAMがあり、実行中のアプリケーションがほとんどないため、単純なgrepでもメモリが不足する可能性があることに本当に驚きました。~/Documents約100GB、さまざまなファイルが含まれています。

grep -RIこの問題はないかもしれませんが、バイナリファイルでも検索したいと思います。

答え1

2つの潜在的な問題:

  • grep -R(OS / X 10.8以降で見つかった修正されたGNUを除くgrep)シンボリックリンクに従ってください。したがって、100 GBのファイルしか存在しない場合でも、~/Documentsシンボリックリンクが残っている可能性があります/。たとえば、ファイルシステム全体を検索します。 ./dev/zero最新のgrep -rGNUと組み合わせて使用​​するgrepか、標準構文を使用するには:

    find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
    

    (ただし、終了状態はパターンが一致したかどうかを反映しないことに注意してください。)

  • grepパターンに一致する線を探します。これを行うには、メモリに一度に1行ずつロードする必要があります。grep他の多くの実装とは異なり、GNUはgrep読み取る行のサイズに制限はなく、バイナリファイル内の検索をサポートしています。そのため、ファイルに使用可能なメモリよりも大きな非常に大きな行(2行改行など)があると失敗します。

    これは通常スパースファイルで発生します。次のコマンドを使用して再現できます。

    truncate -s200G some-file
    grep foo some-file
    

    この問題は解決するのが難しいです。次のことができます(まだGNUを使用していますgrep)。

    find ~/Documents -type f -exec sh -c 'for i do
      tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0"
      done' Milledgeville {} +
    

    入力を提供する前に、一連のNUL文字を改行文字に変換してくださいgrep。これは、スパースファイルによって問題が発生する状況を扱います。

    大容量ファイルに対してのみこれを実行して最適化できます。

    find ~/Documents -type f \( -size -100M -exec \
      grep -He Milledgeville {} + -o -exec sh -c 'for i do
      tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0"
      done' Milledgeville {} + \)
    

    ファイルいいえgrepまれで古いバージョンのGNUを使用している場合は、2.6このオプションを使用できます--mmap。行はメモリにコピーされず、メモリにマップされます。つまり、システムは常にファイルページアウトを介してメモリを回復できます。このオプションはgrepGNU 2.6から削除されました。

答え2

私は通常そうする

find ~/Documents | xargs grep -ne 'expression'

いくつかの方法を試してみたところ、この方法が最速であることがわかりました。名前にスペースが含まれるファイルはうまく処理されません。この状況を知っていて、grepのGNUバージョンがある場合は、次のものを使用できます。

find ~/Documents -print0 | xargs -0 grep -ne 'expression'

それ以外の場合は、次のものを使用できます。

 find ~/Documents -exec grep -ne 'expression' "{}" \;

これにより、exec各ファイルに対してgrep操作が実行されます。

答え3

この問題を解決するいくつかの方法を考えることができます。

  • すべてのファイルを一度にインポートするのではなく、一度に1つのファイルだけを操作してください。例:

      find /Documents -type f -exec grep -H Milledgeville "{}" \;
    
  • どのファイルにこれらの単語が含まれているかを知りたい場合は、代わりにこれを行いgrep -lます。 grepは最初のヒット後に検索を停止するので、大容量ファイルを読み続ける必要はありません。

  • 実際のテキストも必要な場合は、2つの別々のgrepを一緒にまとめることができます。

      for file in $( grep -Rl Milledgeville /Documents ); do \
          grep -H Milledgeville "$file"; done
    

答え4

失われたデータを取得し、メモリ不足エラーが発生するように6TBディスクを準備しています。これは他のファイルにも当てはまります。

私たちが考えた解決策は、ddとgrepを使ってディスクブロックを読み取ることでした。コードは次のとおりです(big-grep.sh)。

#problem: grep gives "memory exhausted" error on 6TB disks
#solution: read it on parts
if [ -z $2 ] || ! [ -e $1 ]; then echo "$0 file string|less -S # greps in chunks"; exit; fi

FILE="$1"
MATCH="$2"

SIZE=`ls -l $1|cut -d\  -f5`
CHUNKSIZE=$(( 1024 * 1024 * 1 )) 
CHUNKS=100 # greps in (100 + 1) x 1MB = 101MB chunks
COUNT=$(( $SIZE / $CHUNKSIZE * CHUNKS ))

for I in `seq 0 $COUNT`; do
  dd bs=$CHUNKSIZE skip=$(($I*$CHUNKS)) count=$(( $CHUNKS+1)) if=$FILE status=none|grep -UF -a --context 6 "$MATCH"
done

関連情報