2013-05-25 2 views
1

Я делаю заполнить потоп на 2000 х 2000 х 256 битовой карты (в памяти), используя код здесь: http://rosettacode.org/wiki/Bitmap/Flood_fill#C.23Очередь выбрасывая исключения памяти в Заливка

Очередь бросает из памяти ошибка при q Count = 33554432 (~ 33MB). Очевидно, у меня больше памяти. Я также создал структуру IntPoint, поэтому каждая точка имеет 2 интервала вместо 2 удвоений.

  1. Есть ли способ вручную выделить больше памяти для очереди?
  2. Если это невозможно, есть ли у кого-нибудь другие предложения?

FYI: Я сомневаюсь, что это важно, но я фактически делаю заливку заливки массивом байтов в 2000 х 2000 в отличие от фактической загрузки растрового изображения, проверки цветов и замены.

Ниже моя реализация Заливки из упомянутой выше ссылки (возможно вопиющая ошибка выскочит):

public struct IntPoint 
    { 
     public int X, Y; 

     public IntPoint(int p1, int p2) 
     { 
      X = p1; 
      Y = p2; 
     } 
    } 


    public void TerrainFloodFill(Point Tpt, byte targetElevation, byte replacementTerrain) 
    { 
     IntPoint pt = new IntPoint((int)Tpt.X, (int)Tpt.Y); 

     Queue<IntPoint> q = new Queue<IntPoint>(); 
     q.Enqueue(pt); 
     while (q.Count > 0) 
     { 
      IntPoint n = q.Dequeue(); 
      if (HeightMap[(int)n.X, (int)n.Y] != targetElevation) 
       continue; 
      IntPoint w = n, e = new IntPoint(n.X + 1, n.Y); 
      while ((w.X > 0) && HeightMap[(int)w.X, (int)w.Y] == targetElevation) 
      { 
       TerrainMap[(int)w.X, (int)w.Y] = replacementTerrain; 
       if ((w.Y > 0) && HeightMap[(int)w.X, (int)w.Y - 1] == targetElevation) 
        q.Enqueue(new IntPoint(w.X, w.Y - 1)); 
       if ((w.Y < MapHeight - 1) && HeightMap[(int)w.X, (int)w.Y + 1] == targetElevation) 
        q.Enqueue(new IntPoint(w.X, w.Y + 1)); 
       w.X--; 
      } 
      while ((e.X < MapWidth - 1) && HeightMap[(int)e.X, (int)e.Y] == targetElevation) 
      { 
       TerrainMap[(int)e.X, (int)e.Y] = replacementTerrain; 
       if ((e.Y > 0) && HeightMap[(int)e.X, (int)e.Y - 1] == targetElevation) 
        q.Enqueue(new IntPoint(e.X, e.Y - 1)); 
       if ((e.Y < MapHeight - 1) && HeightMap[(int)e.X, (int)e.Y + 1] == targetElevation) 
        q.Enqueue(new IntPoint(e.X, e.Y + 1)); 
       e.X++; 
      } 
     } 

    } 

Как всегда, заранее спасибо за помощь!

ответ

1

Это может быть проблема фрагментации, вы должны действительно использовать профилировщик памяти, чтобы узнать, что происходит.

В качестве первого укола,

int estimatedSize = ...; 
    Queue<IntPoint> q = new Queue<IntPoint>(estimatedSize); 

Я думаю, что-то вроде int estimatedSize = MapWidth; будет хорошим началом.


Но ваша очередь по-прежнему становится слишком большой. Исходный алгоритм может завершиться неудачно, когда targetColor == replacementColor, в вашем случае это потому, что HeightMap != TerrainMap. Вам необходимо оперировать на карте такой же картой, чтобы установка «пикселя» была удостовериться, что она не переупорядочивается при рассмотрении ее соседей.

Итак, сначала скопируйте всю карту HeightMap в TerrainMap.

+0

Во-первых, спасибо за предложение. Он запускает OOM около 60 МБ независимо от того, насколько высок я установлен оценочный размер int оценкамSize = MapHeight * MapWidth * sizeof (int) * 2; – zetar

+0

Где (когда) работает? И вы должны вернуться к 'struct'. –

+0

Да, я вернулся к структуре. – zetar

0

Структуры неизменяемы, и каждая их модификация создает новый объект, как и примитивные типы. Я вижу некоторый X ++; и X -; изменения структуры. Попробуйте сделать IntPoint классом вместо этого, чтобы ссылка не продолжала получать new'd и видеть, улучшает ли это что-то.

+0

Структуры _should be_ immutable, этого нет. –

+0

Справа. Я предполагаю, что я имел в виду, он создает много копий структуры, изменяя ее. – Haney

+0

Изменил его для класса, и он стал дальше. Недостаточно памяти: count = 59517893 (~ 59 МБ). Я не знаю, почему это так получилось. – zetar

Смежные вопросы