Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / glDeleteBuffers() и glDeleteTextures() не освобождают память (upd.: освобождают; опечатка - два одинаковых индекса, дважды создавался VAO, а удалялся только один)

glDeleteBuffers() и glDeleteTextures() не освобождают память (upd.: освобождают; опечатка - два одинаковых индекса, дважды создавался VAO, а удалялся только один)

Страницы: 1 2 3 4 Следующая »
Роман ШуваловУчастникwww24 янв. 20189:25#0
Собственно, проблема известная и давно гуглится. Но решения нет. Невозможно заставить драйвер освободить память, выделенную функциями glBufferData() и glTexImage2D().

Более того, в моем случае память не освобождается даже при уничтожении контекста!

    SDL_GL_DeleteContext(rs_app.sdl_ctx);
    sleep_msec(20000);
    SDL_DestroyWindow(rs_app.sdl_win);
    sleep_msec(50000);

Вывод massif выглядит вот так.
По шкале Х - время, измерятся в количестве выполненных млрд. инструкций.
По шкале Y - потребляемая память.
Последние столбцы с неизменным количеством потребляемой памяти, это тот самый sleep().

    MB
427.3^                                           #                            
     |                                           #                            
     |                                          @#                            
     |                                         :@# ::@::  :@::::::@:::::@:::::
     |                                    ::::::@#:::@:::::@::::::@:::::@:::::
     |                             @  @::::: :::@#:::@:::::@::::::@:::::@:::::
     |                       @ :@ @@::@::::: :::@#:::@:::::@::::::@:::::@:::::
     |                    @::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@:::::
     |               @: @:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@:::::
     |            :@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@:::::
     |           ::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@:::::
     |         @:::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@:::::
     |      :::@:::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@:::::
     |      :::@:::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@::::@
     |   @:::::@:::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@::::@
     |:::@:::::@:::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@::::@
     |:::@:::::@:::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@::::@
     |:::@:::::@:::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@::::@
     |:::@:::::@:::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@::::@
     |:::@:::::@:::@:@ :@:@::@::@:@@::@::::: :::@#:::@:::::@::::::@:::::@::::@
   0 +----------------------------------------------------------------------->Gi
     0                                                                   20.41

У меня тут генерируемый мир. При движении игрока старая геометрия за спиной игрока уничтожается, новая впереди создаётся. Но из-за того, что память при удалении не освобождается, через какое-то время память просто заканчивается и всё.

Пробовал передавать в glBufferData() пустой массив, не помогло.

Единственное, что приходит в голову - вместо удаления старых данных писать "поверх них" новые. Правда, не понятно, как поступать, если новых данных больше. Напрашивается мысль создавать по несколько мелких VBO, но у меня есть еще и индексы, которые не смогут "ссылаться" на чужой VBO. Избавиться от индексов, дублировать вершины и рисовать "в лоб" - должно сработать, но как-то все это нерационально.

У кого какие мысли на этот счет?

glasmУчастникwww24 янв. 20189:50#1
под мобильным нет такой проблемы, там буфер ограничен 65k вершинами, потому приходится сразу думать об организации списка буферов
на остальных системах проще фрагментировать один или несколько буферов с более менее универсальными наборами атрибутов
в самых современных системах дополнительно снижены задержки на вывод множества однотипных объектов

и зачем что-то удалять во время игрового процесса ?

Роман ШуваловУчастникwww24 янв. 201810:18#2
glasm
> под мобильным нет такой проблемы, там буфер ограничен 65k вершинами
Серьёзно? А это где-то написано? У меня вершин мягко говоря побольше, чем 65к, ни разу о таком ограничении не слышал.

> и зачем что-то удалять во время игрового процесса ?
Ну я же написал. Игрок переместился в другую часть мира, старый кусок удаляем, новый загружаем (генерируем).

gkv311Постоялецwww24 янв. 201810:28#3
glasm написал 24 янв. 2018:
под мобильным нет такой проблемы, там буфер ограничен 65k вершинами...

"Под мобильный" кем? Это точно сообщение из 2018го года, и кто-то ещё мучается поддержкой Android устройств 5-7милетней давности
(у которых давно умерла батарейка, даже если они сами по себе не превратились в пыль благодаря именитому качеству современных мобильных устройств)?

Роман Шувалов

Серьёзно? А это где-то написано? У меня вершин мягко говоря побольше, чем 65к, ни разу о таком ограничении не слышал.

OpenGL ES 2.0 с его буфером индексов из unsigned 16-bit integer (нормальные 32-битные индексы поддерживаются либо при наличии расширения, либо если устройство OpenGL ES 3.0+).
gkv311Постоялецwww24 янв. 201810:32#4
Роман Шувалов
У меня тут генерируемый мир. При движении игрока старая геометрия за спиной игрока уничтожается, новая впереди создаётся.
Но из-за того, что память при удалении не освобождается, через какое-то время память просто заканчивается и всё.

Тут должно было быть написано, на чём всё это дело тестируется, воспроизводится ли проблема на разных конфигурациях (желательно с разным GPU) и полноценные куски кода вызывающие проблему.
Очевидно, что другие программы тоже создают и удаляют VBO, и как-то справляются с "память при удалении не освобождается" - то есть это либо бага в драйверах, бага в коде или особенности менеджера памяти конкретного OpenGL драйвера, которые воспринимаются как утечки.
PA3UJIbПостоялецwww24 янв. 201811:20#5
А зачем вообще чистить память после glBufferData?
Буфер попользовал, удалил. Та память, что после него осталась, становится ничейной и можно поверх данные накидывать, но уже для нового буфера, со своим glBufferData.
glasmУчастникwww24 янв. 201811:23#6
gkv311
> Это точно сообщение из 2018го года
да, прикинь, на начало 2018 года ЛИШЬ 94% сотовых и 92% планшетов поддерживает 32-битные индексы, а 1/3 устройств не умеют GLES3, включая новые устройства на Android5+ на старых чипах

Роман Шувалов
> старый кусок удаляем, новый загружаем (генерируем).
что значит удаляем ? не рисуем буфер(ы) с кучей объединённых объектов или не рисуем отдельные объекты в той области ?
т.е. что проще, перезапонить буфер вершинами и индексами или обновить список отображаемых объектов... какой метод используется ?
если первый, то буфер, куда переходим, можно заполнять постепенно, а предыдущий просто "перемещаем" дальше, указав, что он пустой

Правка: 24 янв. 2018 11:34

gkv311Постоялецwww24 янв. 201811:28#7
glasm
да, прикинь, на начало 2018 года 94% сотовых и 92% планшетов не поддерживает 32-битные индексы, а 1/3 устройств не умеют GLES3, включая новые устройства на Android5+ на старых чипах

Пруфы в студию.
innuendoПостоялецwww24 янв. 201811:47#9
может vulkan  ?
Роман ШуваловУчастникwww24 янв. 201813:30#10
Для начала скажу, что любой при нехватки памяти всё наглухо виснет. Речь не только про мою разработку, а про любое приложение. По треску HDD предполагаю, что система пытается задействовать своп, хотя своп-раздела у меня не размечено. Спасает только Хард Ресет, хотя иногда отвисает пометкой "Bus error". Но редко. Разбираться с этим как-то руки не дошли.

gkv311
> OpenGL ES 2.0 с его буфером индексов из unsigned 16-bit integer
Ясно. Буду иметь в виду, спасибо.

> Тут должно было быть написано, на чём всё это дело тестируется, воспроизводится ли проблема на разных конфигурациях
ПК, Linux, Intel HD4000. Сегодня протестирую на другом ПК, но сильно сомневаюсь, что ситуация изменится. Даже если изменится, приемлимый "workaround" надо искать и на моём текущем железе.

> и полноценные куски кода вызывающие проблему

glBindBuffer(GL_ARRAY_BUFFER, vboid);
glBufferData(GL_ARRAY_BUFFER, data_len, data, GL_STATIC_DRAW);
// Потрачено data_len байтов
glDeleteBuffers(1, &vboid);
// data_len байтов не освободилось и никогда не будет освобождено. 

gkv311
> Очевидно, что другие программы тоже создают и удаляют VBO, и как-то справляются с "память при удалении не освобождается"
Ну, может им хватает памяти даже с учетом того, что память не освободилась. Но иногда не хватает и всё виснет. Team Fortress 2, помнится, вис, до тех пор пока с течением времени не распух до такой степени, что моё железо перестало его тянуть.

PA3UJIb
> Буфер попользовал, удалил. Та память, что после него осталась, становится
> ничейной и можно поверх данные накидывать, но уже для нового буфера, со своим glBufferData.
В том-то и дело, что эта "ничейная" память на деле не используется и только занимает место. И новые вызовы glBufferData располагаются в новых кусках памяти, а старый висит мёртвым грузом.

innuendo
> может vulkan ?
На изучение нового GAPI и переписыванию всей игры, мягко говоря, нет времени.

ShadowTeologПостоялецwww24 янв. 201813:48#11
сделать контекст точно текущим в этом потоке.
убедиться что ошибки нет
glBindBuffer(GL_ARRAY_BUFFER, vboid);
glBufferData(GL_ARRAY_BUFFER,0, 0, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
уже потом удалить,
удаление текущего буфера может плохо кончиться
Роман ШуваловУчастникwww24 янв. 201815:06#12
Да ёшкин крот! Проблема исчезла! Всё успешно удаляется. Успех был обнаружен после кода ShadowTeolog, но теперь я его стёр и вернул все как было (даже не биндю нулевой буфер) - всё равно все успешно удаляется. Либо я действительно где-то что-то тронул и все само заработало, либо драйвер надо мной издевается.

upd.: Вероятно, я в процессе отладки включил контекст GL2, в нём не использовался VAO, а именно VAO оказался источником проблемы.

Правка: 20 мар. 2018 16:10

AndreyПостоялецwww24 янв. 201815:11#13
glasm
> да, прикинь, на начало 2018 года 94% сотовых и 92% планшетов не поддерживает 32-битные индексы, а 1/3 устройств не умеют GLES3, включая новые устройства на Android5+ на старых чипах
> https://webglstats.com/webgl/extension/OES_element_index_uint
++


Кстати, у Vulkan поддержка 32 битных индеков достпуна только при наличии флага VkPhysicalDeviceFeatures::fullDrawIndexUint32, так что тут все от железа зависит.
Пример устройства которое дежит 32 битные индексы на OpenGL ES 3x, но не держит на Vulkan:
https://vulkan.gpuinfo.org/displayreport.php?id=2359#features

MrShoorУчастникwww24 янв. 201819:08#14
Роман Шувалов
Ставиш CodeXL. Ставишь галки на:
Break on OpenGL Error
Break on Detected Error
Break on Memory Leaks
+ Показать

Запускаешь, играешь, корректно выходишь из игры. Узнаешь много нового. :)

Правка: 24 янв. 2018 19:20

Страницы: 1 2 3 4 Следующая »

/ Форум / Программирование игр / Графика

2001—2018 © GameDev.ru — Разработка игр