View Issue Details

IDProjectCategoryView StatusLast Update
0001220SAS.ПланетаБаг / Bugpublic10-10-2012 11:47
Reportervasketsov Assigned Tovdemidov  
PrioritynormalSeveritymajorReproducibilitysometimes
Status closedResolutionfixed 
PlatformWindowsOSVistaOS VersionUltimate
Product Version.Nightly 
Target Version120808Fixed in Version120808 
Summary0001220: При длительном безостановочном перемещении карты возникает EOutOfMemory (не утечка)
DescriptionЭто описание как отловить и защититься. На примере 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 в голову всем, кто не спрятался. Ну или как-то более фигурно. Покуда в моём примере ТОЛЬКО перемещается карта - соответственно скорее всего речь идёт о подчистке кэша в памяти. НО править именно кэш в памяти очевидно некорректно. Сам по себе кэш в памяти ничего не знает про друге кэши и про других пожирателей памяти. Так что необходимо общее решение.
Steps To Reproduce1. Открываем сас и для наглядности поверх него таскманагер на закладке с пмятью.
2. Сасу вписываем число кэшируемых тайлов несколько тыщ. На самом деле не так уж и много, у мну 3000.
3. Начинаем яростно елозить картой вправо-влево - наблюдаем рост сожранной памяти. В зависимости от скорости работы и количества памяти очевидно тангенс угла наклона линии может быть разный. Не останавливаемся. Может быть минут 10.
4. Когда память кончается - получаем в лицо EOutOfMemory внутри битмапки, наружу исключение вылетает уже текстом, но не суть. Возможно исключение кинется в другом месте. Значит не повезло.
5. После продолжения работы ждём и смотрил глазами в таскманагер. Как придёт мусорщик - сразу использованная память грохнется вниз до первоначальных значений.
TagsNo tags attached.

Activities

Garl

15-03-2012 17:23

manager   ~0006119

гето в недрах u_MapType.pas у меня тоже вылетает при генерации вышележащих слоёв и движении картой.
только количество кэшируемых тайлов у меня всегда 0

vasketsov

15-03-2012 17:32

manager   ~0006120

Серьёзность баги обусловлена ещё и тем, что при езде в машине с GPS-ом карта _постоянно_ перемещается безо всяких мышек и таскманагеров. Соответственно падение традиционно будет происходить в самый ответственный момент.

>в недрах u_MapType.pas
Там в старой ревизии было 2 традиционных места, так как при указанных операциях 99% что свалится на выделении памяти под битмапку - соответственно это либо SetSize либо LoadFromStream.

Garl

15-03-2012 17:45

manager   ~0006121

>Там в старой ревизии было 2 традиционных места,
в ночнушке уже поправлено. утром можно тестить?

vasketsov

15-03-2012 17:51

manager   ~0006122

>в ночнушке уже поправлено
Ни в коем случае. Ловить нехватку памяти в одном конкретном месте очевидно моветон. Я просто пример привёл, как воспроизвести, отловить и придушить.
Кроме того LoadFromStream переписан by vdemidov. Так что где вместо этого будет прилетать - ещё не знаю.
Вощем надо думать как красиво это порешить.

vdemidov

15-03-2012 22:08

manager   ~0006133

Ты садюга. 3000 битмап тайлов это 756 мегабайт. И это только на одину карту или активный слой. И только кэша. Да еще и каша на базе стринглиста. Тобишь Карта+слой+слой с гарантией съедают все доступные 2 гига доступные для процесса.

vasketsov

15-03-2012 22:17

manager   ~0006136

У мну опция стоит в бут.ини, мне 3 гига доступны для процесса.
Но сути это не меняет.
Сделай 1000, включи 5 слоёв - и получишь то же самое.

vdemidov

15-03-2012 22:22

manager   ~0006137

3 гига доступны для процессов, которые скомпилены с поддержкой 3-х гигов, а САС к таким не отоносится.
1000 и 5 слоев это тоже почти полтора гига. Вот если на 1000 и 1 слое добьешься аут оф мемори, тогда посмотрим.

vasketsov

15-03-2012 22:41

manager   ~0006140

>Вот если на 1000 и 1 слое
У меня в движении меньше 5 слоёв не бывает (не считая меток).
На один экран сейчас влазит 54 тайла - итого даже 20-ти экранов нет, и 1000 готова.
В общем это конечно мало, да и ограничений-то как бы нет в программе.

vdemidov

16-03-2012 05:04

manager   ~0006149

>На один экран сейчас влазит 54 тайла - итого даже 20-ти экранов нет, и 1000 готова.
Увы. Поэтому и говорю, что нужно делать дополнительно кэширование нераспакованных
тайлов на уровне тайлохранилища.
И еще. Используемый сейчас кэш, очень тупой и время поиска линейное от количества элементов в нем. То есть чем больше, тем медленее. Поэтому максимальное разумное значение 300-500 тайлов на слой.
> В общем это конечно мало, да и ограничений-то как бы нет в программе.
Ну надо конечно сделать подсчет размера кэша и ограничение по суммарному размеру, но ИМХО сложно, трудоемко и не сильно критично.

vdemidov

20-03-2012 15:21

manager   ~0006229

Добавил ограничение на максимальный размер кэша в памяти.

Issue History

Date Modified Username Field Change
15-03-2012 16:51 vasketsov New Issue
15-03-2012 17:23 Garl Note Added: 0006119
15-03-2012 17:24 Garl Relationship added related to 0001215
15-03-2012 17:32 vasketsov Note Added: 0006120
15-03-2012 17:45 Garl Note Added: 0006121
15-03-2012 17:51 vasketsov Note Added: 0006122
15-03-2012 22:08 vdemidov Note Added: 0006133
15-03-2012 22:08 vdemidov Relationship deleted related to 0001215
15-03-2012 22:17 vasketsov Note Added: 0006136
15-03-2012 22:22 vdemidov Note Added: 0006137
15-03-2012 22:41 vasketsov Note Added: 0006140
16-03-2012 05:04 vdemidov Note Added: 0006149
20-03-2012 15:21 vdemidov Note Added: 0006229
20-03-2012 15:21 vdemidov Status new => resolved
20-03-2012 15:21 vdemidov Fixed in Version => 120808
20-03-2012 15:21 vdemidov Resolution open => fixed
20-03-2012 15:21 vdemidov Assigned To => vdemidov
24-03-2012 21:39 vdemidov Target Version => 120808
10-10-2012 11:47 Tolik Status resolved => closed
08-08-2025 13:22 zed Category Баг => Баг / Bug