2012-03-26 61 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

相关问题