LINUX.ORG.RU

[c++][ничегонепонимат] Не работет delete/free

 


0

1

Есть структура «анимация» - тупо набор RGBA-кадров, есть класс - анимированная текстура, в котором загружаются все кадры в OpenGL и потом уже используются ID текстур. Проблема с очисткой изначальной анимации. Вот код конструктора:

AnimatedTexture::AnimatedTexture(const Animation& a)
{
    realWidth = a.width;
    realHeight = a.height;
    frameCount = a.frameCount;

    textureIDs = new GLuint[frameCount];
    glGenTextures(frameCount, textureIDs);
    
    for (int i = 0; i < frameCount; i++)
    {
        glBindTexture(GL_TEXTURE_2D, textureIDs[i]);
	
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, a.frames[i].width, a.frames[i].height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, a.frames[i].data);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        //delete[] a.frames[i].data; //<- тут удаляется
    }
    for(int i = 0; i < frameCount; i++)
    {
        delete[] a.frames[i].data; //<- а тут нет 0_0
    }
}
Если использовать первый delete[] - память освобождается, но он мне там не нужен (на самом деле отчистка должна быть вне класса). А вот второй не работает (цикл исправен - проверял). Что это вообще может быть?! Без glTexImage2D все очищается и во втором случае.

Программа работает корректно в обоих случаях, только в первом занимает 350 Мб (Анимация - 300 Мб без сжатия), а во втором - 700.

Пока проверял только на Gentoo x86_64.

★★★★

Последнее исправление: Kosyak (всего исправлений: 1)

glTexImage2D вроде не должен изменять память, но, похоже, изменяет. Смотрел в дебаггере?

Независимо от этого, освобождать действительно нужно не здесь.
Обязательно ли нужно самому работать с памятью? Почему бы не взять std::vector?

JackyTreehorn
()

Как ты проверял освобождается ли память «на самом деле»?

Может дело в том, что у тебя нет вызова glDeleteTextures?

anonymous
()
Ответ на: комментарий от anonymous

Как ты проверял освобождается ли память «на самом деле»?

Если использовать delete[] в первом цикле, то программа занимает ~370 метров, если тот, что в отдельном цикле - ~700 метров, т.е. видно, что текстуры остаются в двух местах - внутри openGL и a.frames[].data. Если же оставить отдельный цикл и убрать glTexImage2D(), то a.frames[].data освобождается.

Kosyak ★★★★
() автор топика
Ответ на: комментарий от JackyTreehorn

Если б изменял, то первый delete[] бы тоже не работал.

Бегло просматривал - вроде не изменяет...

Kosyak ★★★★
() автор топика
Ответ на: комментарий от kiverattes

Там нет ничего интересного и он тут не причем:

AnimatedTexture::~AnimatedTexture()
{
    glDeleteTextures(frameCount, textureIDs);
}

Kosyak ★★★★
() автор топика
Ответ на: комментарий от Kosyak

delete же не отдает память обратно ОС? сам с таким помню сталкивался, вроде delete сделал, а прога все равно много памяти жрет (правда через какое-то время все нормально)

valgrind'ом прогони или гугловым перфтулом

kulti ★★
()

Хм, на арче x86 все работает...

Значит дело либо в x86_64, либо в генте.

//Если кому интересно - везде nvidia блоб.

Kosyak ★★★★
() автор топика
Ответ на: комментарий от shty
struct Frame
{
    int width;   //!< Frame width
    int height;   //!< Frame height
    unsigned char *data; //!< Frame data (in RGBA format)
};
struct Animation
{
    int width;   //!< Animation width
    int height;   //!< Animation height
    int frameCount;  //!< Number of frames in animation
    Frame *frames;  //!< Animation frames
};
Kosyak ★★★★
() автор топика
Ответ на: комментарий от shty
    Frame result
    /*....*/
    unsigned char *rgba = new unsigned char[width * height * 4];
    memset(rgba, 0, width * height * 4);
    /* Тут некая запись в rgba из файла*/
    result.data = rgba;
    return result;
Kosyak ★★★★
() автор топика

Клёви десигн, конструктор одной хрени коцает содержимое другой...

И почему, не вектор?

nikitos ★★★
()
Ответ на: комментарий от nikitos

Клёви десигн, конструктор одной хрени коцает содержимое другой.

читай внимательней:

но он мне там не нужен (на самом деле отчистка должна быть вне класса)

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

Почему в первом случае удаляет, а во втором (который символизирует удаление вне класса, если чо) нет?! Причем это проявилось пока только на gentoo x86_64, на арче x86 все норм.

Не вектор, потому что это низкоуровневые данные, у меня там есть всякие разные трансформации с пикселями.

Kosyak ★★★★
() автор топика
Ответ на: комментарий от Kosyak

Потому что его там нет, я считаю. Полчаса потратил на поиск подтверждения своих слов - нашел только разрозненные обсуждения на форумах. В общем, повторюсь еще раз: все зависит от того, как реализована работа с памятью. delete может и не возвращать память ОС, а просто помечает ее, как свободную для аллокатора. Суть в том, что память может выделятся большими блоками прозапас, чтобы фрагментация меньше была. Думаю, вам просто повезло =)

kulti ★★
()
Ответ на: комментарий от Kosyak

Не вектор, потому что это низкоуровневые данные, у меня там есть всякие разные трансформации с пикселями.

char* buf = &rgba.front();

в функции с трансформациями не подойдет?

aho
()
Ответ на: комментарий от Kosyak

Не вектор, потому что это низкоуровневые данные, у меня там есть всякие разные трансформации с пикселями.

Эм... и как это мешает использованию вектора? Вектор выделят непрерывный кусок памяти под данные, как и new[]. Доступ на начало этих данных, если нужно работать с уазателями, тоже легко получить: &a.frames.data[0]. И не придется беспокоится о забыл/не забыл сделать delete.

kulti ★★
()
Ответ на: комментарий от kulti

Ну я подумаю над этим.

У меня есть отдельная библиотека, котороя собственно загружает Animation, Frame и т.д., я планировал сделать её C-совместимой.

Kosyak ★★★★
() автор топика
Ответ на: комментарий от Kosyak

тогда, на первый взгляд, всё должно работать правильно в случае data, подробнеее надо смотреть уже выхлоп valgrind

кроме того, Вы должны чистить не только data, но и frames

раз уж Вы используете C++ и хотите именно указатель - используйте smart pointers, имхо лучшее решение для Вас

так же можно использовать std::vector, из него тоже можно выдрать c-style array: &v[0] - указатель на первый элемент, аналогичный frames например

shty ★★★★★
()
Ответ на: комментарий от Kosyak

> Поясню для розовых существ с хвостом:

Э, а почему бы не задавать вопросы так, чтоб розовые существа с хвостом не плодились?

Наводящий вопрос:

Почему в первом случае удаляет, а во втором нет?!

это исходя из чего сделан такой вывод что нет? Валгринд, детка, не панацея. Напейши свой new, тогда будешь говорить что нет.

nikitos ★★★
()
Ответ на: комментарий от shty

frames чистится, просто я его не вставил сюда.

Смарт-поинтеры тоже вовсю использую...

//Блин, просто даже причину не могу придумать, почему так происходит...

Kosyak ★★★★
() автор топика
Ответ на: комментарий от Kosyak

попробуй забить оперативку на полную. Виртуалочку там запустить ;) Если после того как вся память сожрётся, память под приложение вернется в норму, значит всё ок.

stevejobs ★★★★☆
()
Ответ на: комментарий от Kosyak

Смарт-поинтеры тоже вовсю использую...

в приведённом отрывке кода этого не видно

Блин, просто даже причину не могу придумать, почему так происходит...

ну, удалённо по обрывкам кода я точнее сказать не могу

shty ★★★★★
()

Мне кажется возможны две причины:

1. Выход за пределы массива a.frames.data . Например выделял в памяти по одним width и height, а работал по другим.

2. Где-то в другом месте повреждается память, а здесь мы видим лишь побочный эффект. Соответственно, проблему надо искать в совершенно другом месте.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Valgrind показал бы, не?

Тем более, по опыту, libc очень хорошо heap corrupt отлавливает.

Kosyak ★★★★
() автор топика

Так, под Windows XP x32 (MSVC) тоже замечательно работает, причем там похоже текстуры вообще сразу в видеокарту засовываются, потому что всего 16 Мб занято.

Kosyak ★★★★
() автор топика
Ответ на: комментарий от Kosyak

Это х#$ня, я не тест. Память в хипе, видимо, свободна, но ОС не отдана. И если ты снова попытаешься зааллоцировать столько же таких элементов — то у тебя размер отжираемой программой виртуальной памяти не изменится.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.