SASGIS - SAS.Планета
View Issue Details
0001220SAS.Планета[All Projects] Багpublic15-03-2012 16:5110-10-2012 11:47
vasketsov 
vdemidov 
normalmajorsometimes
closedfixed 
WindowsVistaUltimate
.Nightly 
120808120808 
0001220: При длительном безостановочном перемещении карты возникает EOutOfMemory (не утечка)
Это описание как отловить и защититься. На примере u_MapType.pas.

1. Создаём функцию
function CatchedOutOfMemory(const AException: Exception): Boolean;
begin
  Result := Assigned(AException) and
            ((AException is EOutOfMemory) or (System.Pos('out of memory', LowerCase(AException.Message))>0));
end;

2. Внутри TMapType.LoadTileFromPreZ ищем spr.SetSize и заменяем его на:
              try
                spr.SetSize(VTileTargetBounds.Right, VTileTargetBounds.Bottom);
              except
                on E: Exception do begin
                  if CatchedOutOfMemory(E) then begin
                    // cleanup
                    if Assigned(FCacheBitmap) then
                      FCacheBitmap.Clear;
                    if Assigned(FCacheVector) then
                      FCacheVector.Clear;
                    // repeat
                    spr.SetSize(VTileTargetBounds.Right, VTileTargetBounds.Bottom);
                  end else begin
                    raise;
                  end;
                end;
              end;

Теперь если память заюзана под завязку (скажем, все 3 гига), данный кусок отловит исключение из битмапки, подчистит и не даст мгновенно умереть.
Если после этого ничего не двигать и ещё подождать, то сработает сборщик мусора и соберёт вообще всё что нагуляли. То есть это не утечка.

Итого - надо научиться звать сборщик мусора, чтобы он не доводил до того, что памяти больше нету. Даже если обсуживаемая им сущность вовсю юзается, при достижении определённой границы оставшейся доступной памяти он должен исполнять контрольный TTL в голову всем, кто не спрятался. Ну или как-то более фигурно. Покуда в моём примере ТОЛЬКО перемещается карта - соответственно скорее всего речь идёт о подчистке кэша в памяти. НО править именно кэш в памяти очевидно некорректно. Сам по себе кэш в памяти ничего не знает про друге кэши и про других пожирателей памяти. Так что необходимо общее решение.
1. Открываем сас и для наглядности поверх него таскманагер на закладке с пмятью.
2. Сасу вписываем число кэшируемых тайлов несколько тыщ. На самом деле не так уж и много, у мну 3000.
3. Начинаем яростно елозить картой вправо-влево - наблюдаем рост сожранной памяти. В зависимости от скорости работы и количества памяти очевидно тангенс угла наклона линии может быть разный. Не останавливаемся. Может быть минут 10.
4. Когда память кончается - получаем в лицо EOutOfMemory внутри битмапки, наружу исключение вылетает уже текстом, но не суть. Возможно исключение кинется в другом месте. Значит не повезло.
5. После продолжения работы ждём и смотрил глазами в таскманагер. Как придёт мусорщик - сразу использованная память грохнется вниз до первоначальных значений.
No tags attached.
Issue History
15-03-2012 16:51vasketsovNew Issue
15-03-2012 17:23GarlNote Added: 0006119
15-03-2012 17:24GarlRelationship addedrelated to 0001215
15-03-2012 17:32vasketsovNote Added: 0006120
15-03-2012 17:45GarlNote Added: 0006121
15-03-2012 17:51vasketsovNote Added: 0006122
15-03-2012 22:08vdemidovNote Added: 0006133
15-03-2012 22:08vdemidovRelationship deletedrelated to 0001215
15-03-2012 22:17vasketsovNote Added: 0006136
15-03-2012 22:22vdemidovNote Added: 0006137
15-03-2012 22:41vasketsovNote Added: 0006140
16-03-2012 05:04vdemidovNote Added: 0006149
20-03-2012 15:21vdemidovNote Added: 0006229
20-03-2012 15:21vdemidovStatusnew => resolved
20-03-2012 15:21vdemidovFixed in Version => 120808
20-03-2012 15:21vdemidovResolutionopen => fixed
20-03-2012 15:21vdemidovAssigned To => vdemidov
24-03-2012 21:39vdemidovTarget Version => 120808
10-10-2012 11:47TolikStatusresolved => closed

Notes
(0006119)
Garl   
15-03-2012 17:23   
гето в недрах u_MapType.pas у меня тоже вылетает при генерации вышележащих слоёв и движении картой.
только количество кэшируемых тайлов у меня всегда 0
(0006120)
vasketsov   
15-03-2012 17:32   
Серьёзность баги обусловлена ещё и тем, что при езде в машине с GPS-ом карта _постоянно_ перемещается безо всяких мышек и таскманагеров. Соответственно падение традиционно будет происходить в самый ответственный момент.

>в недрах u_MapType.pas
Там в старой ревизии было 2 традиционных места, так как при указанных операциях 99% что свалится на выделении памяти под битмапку - соответственно это либо SetSize либо LoadFromStream.
(0006121)
Garl   
15-03-2012 17:45   
>Там в старой ревизии было 2 традиционных места,
в ночнушке уже поправлено. утром можно тестить?
(0006122)
vasketsov   
15-03-2012 17:51   
>в ночнушке уже поправлено
Ни в коем случае. Ловить нехватку памяти в одном конкретном месте очевидно моветон. Я просто пример привёл, как воспроизвести, отловить и придушить.
Кроме того LoadFromStream переписан by vdemidov. Так что где вместо этого будет прилетать - ещё не знаю.
Вощем надо думать как красиво это порешить.
(0006133)
vdemidov   
15-03-2012 22:08   
Ты садюга. 3000 битмап тайлов это 756 мегабайт. И это только на одину карту или активный слой. И только кэша. Да еще и каша на базе стринглиста. Тобишь Карта+слой+слой с гарантией съедают все доступные 2 гига доступные для процесса.
(0006136)
vasketsov   
15-03-2012 22:17   
У мну опция стоит в бут.ини, мне 3 гига доступны для процесса.
Но сути это не меняет.
Сделай 1000, включи 5 слоёв - и получишь то же самое.
(0006137)
vdemidov   
15-03-2012 22:22   
3 гига доступны для процессов, которые скомпилены с поддержкой 3-х гигов, а САС к таким не отоносится.
1000 и 5 слоев это тоже почти полтора гига. Вот если на 1000 и 1 слое добьешься аут оф мемори, тогда посмотрим.
(0006140)
vasketsov   
15-03-2012 22:41   
>Вот если на 1000 и 1 слое
У меня в движении меньше 5 слоёв не бывает (не считая меток).
На один экран сейчас влазит 54 тайла - итого даже 20-ти экранов нет, и 1000 готова.
В общем это конечно мало, да и ограничений-то как бы нет в программе.
(0006149)
vdemidov   
16-03-2012 05:04   
>На один экран сейчас влазит 54 тайла - итого даже 20-ти экранов нет, и 1000 готова.
Увы. Поэтому и говорю, что нужно делать дополнительно кэширование нераспакованных
тайлов на уровне тайлохранилища.
И еще. Используемый сейчас кэш, очень тупой и время поиска линейное от количества элементов в нем. То есть чем больше, тем медленее. Поэтому максимальное разумное значение 300-500 тайлов на слой.
> В общем это конечно мало, да и ограничений-то как бы нет в программе.
Ну надо конечно сделать подсчет размера кэша и ограничение по суммарному размеру, но ИМХО сложно, трудоемко и не сильно критично.
(0006229)
vdemidov   
20-03-2012 15:21   
Добавил ограничение на максимальный размер кэша в памяти.