Повторные вызовы image.png.Decode () приводят к ошибкам нехватки памяти - PullRequest
3 голосов
/ 26 марта 2012

Я пытаюсь сделать то, что изначально считал довольно простым. Для остроумия:

Для каждого файла в списке входных файлов:

  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 (), но я не думаю, что?

Продолжение:

После вставки runtime.GC () после каждого вызова greyLevels использование памяти выравнивается. Прошлой ночью я набрал около 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 изображений.

Ответы [ 2 ]

1 голос
/ 26 марта 2012

Похоже, что вы используете 32-битный компьютер.Вполне вероятно, что программе не хватает памяти, потому что сборщик мусора в Go является консервативным.Консервативный сборщик мусора может не обнаружить, что некоторая область памяти больше не используется.В настоящее время не существует обходного пути для этого в программах Go, за исключением исключения структур данных, которые сборщик мусора не может обработать (таких как: struct {...; binaryData [256]byte})

Попробуйте вызывать runtime.GC() в каждой итерации цикла, в которомВызываем функцию greyLevel.Возможно, это поможет программе обработать больше изображений.

Если вызов runtime.GC() не улучшит ситуацию, вы можете изменить свою стратегию, чтобы программа обрабатывала меньшее количество файлов PNG за цикл.

0 голосов
/ 26 марта 2012

Похоже, проблема 3173 , которая была недавно исправлена.Не могли бы вы повторить с последним еженедельным?(Предполагается, что вы сейчас используете какую-то версию до 2012-03-07).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...