2012-03-26 11 views
3

私は当初考えていたことをかなり簡単にしようとしています。image.png.Decode()への繰り返し呼び出しによりメモリ不足エラーが発生する

入力ファイルのリスト内のすべてのファイルの場合:

  1. が、それは「グレーかどうかを確認するために、ファイルやテスト内のすべてのピクセルをスキャンpng.Decode()でファイルを開きウィットに"
  2. イメージの「グレー」ピクセルの割合を返します。

この私が呼び出しています関数です。

func greyLevel(fname string) (float64, string) { 
    f, err := os.Open(fname) 
    if err != nil { 
      return -1.0, "can't open file" 
    } 
    defer f.Close() 

    i, err := png.Decode(f) 
    if err != nil { 
      return -1.0, "unable to decode" 
    } 

    bounds := i.Bounds() 

    var lo uint32 = 122 // Low grey RGB value. 
    var hi uint32 = 134 // High grey RGB value. 
    var gpix float64 // Grey pixel count. 
    var opix float64 // Other (non-grey) pixel count. 
    var tpix float64 // Total pixels. 

    for x := bounds.Min.X; x < bounds.Max.X; x++ { 
      for y := bounds.Min.Y; y < bounds.Max.Y; y++ { 
        r, g, b, _ := i.At(x, y).RGBA() 
        if ((r/255)-1 > lo && (r/255)-1 < hi) && 
          ((g/255)-1 > lo && (g/255)-1 < hi) && 
          ((b/255)-1 > lo && (b/255)-1 < hi) { 
          gpix++ 
        } else { 
          opix++ 
        } 
        tpix++ 
      } 
    } 
    return (gpix/tpix) * 100, "" 
} 

func main() { 
    srcDir := flag.String("s", "", "Directory containing image files.") 
    threshold := flag.Float64("t", 65.0, "Threshold (in percent) of grey pixels.") 
    flag.Parse() 

    dirlist, direrr := ioutil.ReadDir(*srcDir) 
    if direrr != nil { 
      log.Fatalf("Error reading %s: %s\n", *srcDir, direrr) 
    } 

    for f := range dirlist { 
      src := path.Join(*srcDir, dirlist[f].Name()) 

      level, msg := greyLevel(src) 

      if msg != "" { 
        log.Printf("error processing %s: %s\n", src, msg) 
        continue 
      } 

      if level >= *threshold { 
        log.Printf("%s is grey (%2.2f%%)\n", src, level) 
      } else { 
        log.Printf("%s is not grey (%2.2f%%)\n", src, level) 
      } 
    } 
} 

ファイルが比較的小さい(960x720、8ビットRGB)

私はリストを生成するために)(ioutil.ReadDirを呼び出していますスライスをループしてgreyLevel()を呼び出します。

した後で(> 4000のリストのうち)スクリプトパニック約155のファイル:

runtime: memory allocated by OS not in usable range 
runtime: out of memory: cannot allocate 2818048-byte block (534708224 in use) 
throw: out of memory 

私は、私が行方不明ですシンプルなものがある把握。私はGoがgreyLevels()に割り当てられたメモリの割り当てを解除すると思ったが、そうは思わないだろうか?

はフォローアップ:

greyLevelsのすべての呼び出し後runtime.GCを()を挿入した後、メモリ使用量をならし。昨夜、私は約800枚の画像に向かっていきました。今日私はそれを入力セット全体、約6800の画像上で実行させました。 1500枚の画像の後

は、トップは次のようになります。

top - 10:30:11 up 41 days, 11:47, 2 users, load average: 1.46, 1.25, 0.88 
Tasks: 135 total, 2 running, 131 sleeping, 1 stopped, 1 zombie 
Cpu(s): 49.8%us, 5.1%sy, 0.2%ni, 29.6%id, 15.0%wa, 0.0%hi, 0.3%si, 0.0%st 
Mem: 3090304k total, 2921108k used, 169196k free,  2840k buffers 
Swap: 3135484k total, 31500k used, 3103984k free, 640676k cached 

    PID USER  PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 
28474 mtw  20 0 2311m 1.8g 412 R 99 60.5 16:48.52 8.out 

、別の5000枚の画像を処理した後、堅調に推移しました。

+0

Goバージョン、OSプラットフォーム、CPUアーキテクチャ情報を追加してください。また、問題を再現する完全なコードが役立ちます。 – zzzz

+0

@jnml "out of memory ..."(534708224使用中)からCPUアーキテクチャを推論することができます。 –

+0

@Atom:IntelまたはARM? ;-) – zzzz

答えて

1

32ビットマシンを使用しているようです。 Goのガベージコレクタは保守的なので、プログラムがメモリ不足になる可能性があります。保守的なガベージコレクタは、メモリの一部の領域が使用されなくなったことを検出できない可能性があります。

あなたが機能greyLevelを呼び出すされているループの各反復でruntime.GC()を呼び出すようにしてください:(struct {...; binaryData [256]byte}など)ガベージコレクタが処理できないデータ構造を回避以外の囲碁プログラムで、このための回避策はありません。多分それはプログラムがより多くのイメージを処理するのを助けるでしょう。

runtime.GC()を呼び出すと状況が改善されない場合は、プログラムが実行ごとに少数のPNGファイルを処理するように戦略を変更できます。

+0

runtime.GC()はそのトリックを行います。常駐メモリは568Mに上昇し、安定して保持されます。あまりにもこのような回避策が必要ですが、Goの開発者が修正プログラムを作成すると確信しています。ありがとう! – mtw

+0

私はGCが上記の構造体を扱うことができないと主張し、Goのいくつかの特定のデータを避ける必要があるとは思わない(少なくとも最近は)。 – zzzz

+0

@mtw:GCが自動的に起動するはずです。プログラムが手動で実行時にruntime.GC()を呼び出す必要がある場合は、実行時のバグが疑わしいと思っている以上に動作する可能性があります。 – zzzz

0

最近修正された問題3173のようです。あなたは最新の週刊で再試行できますか? (2012-03-07以前のバージョンを使用していると仮定します)。

+0

OK、cool私はweekly.2012-03-22バージョンを実行しています。プロセスはメモリを正常に割り当てますが、ゴミが収集されないようです。 – mtw

関連する問題