2012-03-26 183 views
3

我正在嘗試執行我原本以爲會非常簡單的操作。即:對image.png.Decode()的重複調用會導致內存不足錯誤

對於輸入文件列表中每個文件:

  1. 打開與png.Decode()文件
  2. 掃描文件和測試中的每個像素,看它是否是「灰色」。
  3. 返回圖像中「灰色」像素的百分比。

這是我調用該函數:

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()。

後約155文件(滿分> 4000列表)的腳本恐慌:

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 2012-03-26 07:48:38

+0

@jnml您可以從「內存不足...(534708224正在使用)」推斷CPU架構。 – 2012-03-26 08:43:25

+0

@Atom:Intel還是ARM? ;-) – zzzz 2012-03-26 08:58:03

回答

1

看來您使用的是32位機器。由於Go的垃圾收集器很保守,因此程序可能會耗盡內存。保守的垃圾收集器可能無法檢測到某個區域的內存不再被使用。目前在比避免垃圾收集器無法處理的數據結構(如:struct {...; binaryData [256]byte})其他圍棋程序沒有解決此

試圖調用runtime.GC()在你所調用函數greyLevel循環的每個迭代。也許它會幫助程序處理更多圖像。

如果調用runtime.GC()未能改善您的情況,您可能需要更改策略,以便程序在每次運行時處理更少數量的PNG文件。

+0

runtime.GC()有訣竅。居民記憶上升到568M,然後保持穩定。太糟糕了這樣的解決方法是必需的,但我相信Go開發人員會產生修復。謝謝! – mtw 2012-03-26 10:12:43

+0

我不認爲關於GC的聲明不能處理上面的結構,並且關於需要避免Go中的某些特定數據是真實的(至少現在)。 – zzzz 2012-03-26 10:24:06

+0

@mtw:GC應該自動啓動。如果該程序需要手動調用runtime.GC()才能工作,否則我懷疑運行時可能會出現一個錯誤。 – zzzz 2012-03-26 10:26:57

0

似乎是最近修復的問題3173。您可以請最近的每週重試一次嗎? (假設你現在使用一些預先2012-03-07版本)。

+0

好吧,酷我運行版本weekly.2012-03-22和現在該進程正常分配內存,但它似乎像垃圾沒有收集。 – mtw 2012-03-26 09:55:12

相關問題