Russian Qt Forum
Сентябрь 23, 2024, 06:23 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3 ... 7   Вниз
  Печать  
Автор Тема: Memory issues  (Прочитано 53505 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Сентябрь 13, 2009, 21:50 »

Добрый вечер

Обнаружил проблему с памятью на своей платформе (Mac). Не хочу "предъявлять претензий" (все равно решать самому  Улыбающийся) но сообщить о проблеме по-моему надо.

----------------------------

Hello Qt

I've got a problem with QList memory allocation.

Platform: Mac OSX 10.5.2
Qt versioion:  4.5.2 (Carbon)

Problem description: memory is not released as it's expected. The listing is:

Код:
#include <QtCore/QCoreApplication>
#include <iostream>
#include <stdio.h>

#define  NUM_TEST   (200LL * 1024 * 1024)

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

int i;
QList<int> theList;
for (i = 0; i < NUM_TEST; ++i)
theList.append(qrand());

printf("Press Enter 1\r");
getc(stdin);

theList.erase(theList.begin() + NUM_TEST / 4, theList.begin() + NUM_TEST / 4 * 3);

printf("Press Enter 2\r");
getc(stdin);

return 0;
}

However, the Activity Monitor shows no memory released at point "2" (see screenshot). Using several such QList(s) I have qFatal (no memory exception) very fast. Looking source codes I can guess the problem is related with using  ::realloc that does not release memory in fact.

Thank you
Igor & Igor
(Russian Qt forum)

---------------------
Записан
Winstrol
Гость
« Ответ #1 : Сентябрь 14, 2009, 10:33 »

Добрый вечер

Обнаружил проблему с памятью на своей платформе (Mac). Не хочу "предъявлять претензий" (все равно решать самому  Улыбающийся) но сообщить о проблеме по-моему надо.
Деструктор Qlist в точке 2 еще не отработал, поэтому и память не отдал.
Записан
Tonal
Гость
« Ответ #2 : Сентябрь 14, 2009, 10:43 »

Кроме того, в точке 2 не вызывался деструктор QCoreApplication-а, а так же деструкторы глобальных и статических объектов, которые вызавутся только после окончания работы main.

Так что пока нужно учить язык а не багрепорты отправлять. Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Сентябрь 14, 2009, 11:35 »

Деструктор Qlist в точке 2 еще не отработал, поэтому и память не отдал.
Деструктор здесь ни при чем. Я сказал контейнеру выкинуть половину элементов, но это не освободило часть памяти - занято столько же. 
Записан
Winstrol
Гость
« Ответ #4 : Сентябрь 14, 2009, 12:32 »

Деструктор Qlist в точке 2 еще не отработал, поэтому и память не отдал.
Деструктор здесь ни при чем. Я сказал контейнеру выкинуть половину элементов, но это не освободило часть памяти - занято столько же. 
http://qt.nokia.com/doc/main-snapshot/qlist.html
Note that the internal array only ever gets bigger over the life of the list. It never shrinks. The internal array is deallocated by the destructor and by the assignment operator, when one list is assigned to another.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Сентябрь 14, 2009, 13:00 »

http://qt.nokia.com/doc/main-snapshot/qlist.html
Note that the internal array only ever gets bigger over the life of the list. It never shrinks. The internal array is deallocated by the destructor and by the assignment operator, when one list is assigned to another.
Оба-нв! Спасибо, я это просмотрел. Хорошо что запостил сначала здесь  Улыбающийся
Но у меня и QVector не освобождает

Код:
#include <QtCore/QCoreApplication>
#include <iostream>
#include <stdio.h>
#include <QVector>

#define  NUM_TEST (200LL * 1024 * 1024)

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

int i;
QVector<int> theVector;
for (i = 0; i < NUM_TEST; ++i)
theVector.append(qrand());

printf("Press Enter 1\r");
getc(stdin);

theVector.resize(NUM_TEST / 2);

printf("Press Enter 2\r");
getc(stdin);

return 0;
}
Есть ли какой-то контейнер который память нормально отдает?
Спасибо
Записан
Winstrol
Гость
« Ответ #6 : Сентябрь 14, 2009, 13:11 »

Есть ли какой-то контейнер который память нормально отдает?
Спасибо
Не всегда можно память просто так отдать, если она большими кусками выделяется. Например, в стандартных stl-аллокаторах метода realloc нет. Для этого надо выделить новый кусок, скопировать туда то, что нужно сохранить, затем отдать весь старый кусок.
То есть заводишь временный контейнер, делаешь qSwap с используемым, затем, если такой метод есть, делаешь reserve с нужным новым размером контейнера, и копируешь туда что надо из старого. Все это делаешь в отдельном scope {}, чтобы при выходе из него память из временного объекта освободилась.
« Последнее редактирование: Сентябрь 14, 2009, 13:14 от Winstrol » Записан
spectre71
Гость
« Ответ #7 : Сентябрь 14, 2009, 13:13 »

При реализации подобных списков, обычно имеем:
- Count - кол-во элементов в списке
- Capacity - кол-во места под элементы списка
При добавлении элементов проверяется кол-во доступного места и при нехватке делается переаллокация обычно с запасом.
При удалении элементов кол-во доступного места под элементы не сокращается, соответственно память не освобождается.
Обычно для уменьшения кол-ва выделенной памяти (Capacity == Count или Capacity = Value) делается специальный метод. Насколько я понял в QList его нет и это очень плохо!
У QVector смотри:
void QVector::squeeze ()
int QVector::capacity () const
void QVector::reserve ( int size )
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Сентябрь 14, 2009, 13:25 »

Для полноты картины (мол, чем проверяешь и можно ли этому верить).
Код:
	#define  NUM_TEST		(200LL * 1024 * 1024)

int i, j;
QVector<int> theVector[10];

for (i = 0; i < 10; ++i) {
theVector[i].reserve(NUM_TEST);
for (j = 0; j < NUM_TEST; ++j)
theVector[i].append(1);
theVector[i].resize(2);
theVector[i].squeeze();
}
Вылетает, консоль пишет
Код:
[Session started at 2009-09-14 13:11:02 +0300.]
realloc(508) malloc: *** mmap(size=838864896) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
Ну вот, хотел наконец подучить стандартные классы да видно не судьба  Показает язык
Записан
Winstrol
Гость
« Ответ #9 : Сентябрь 14, 2009, 13:58 »

А так если?
Код
C++ (Qt)
#include <vector>
...
   int i, j;
   std::vector<int> theVector[10];
 
   for (i = 0; i < 10; ++i)
   {
       theVector[i].reserve(NUM_TEST);
       for (j = 0; j < NUM_TEST; ++j)
           theVector[i].push_back(1);
       theVector[i].resize(2);
       {
           std::vector<int> t;
           std::swap(theVector[i],t);
           theVector[i]=t;
           std::cout << theVector[i].capacity() << std::endl;
       }
   }
Записан
spectre71
Гость
« Ответ #10 : Сентябрь 14, 2009, 14:01 »

Так работает
Код
C++ (Qt)
QVector<int> *theVector1;
QVector<int> *theVector2;
 
theVector1 = new QVector<int>;
theVector1->reserve(200*1024*1024);
theVector1->squeeze();
delete theVector1;
 
theVector2 = new QVector<int>;
theVector2->reserve(200*1024*1024);
delete theVector2;

Так падает
Код
C++ (Qt)
QVector<int> *theVector1;
QVector<int> *theVector2;
 
theVector1 = new QVector<int>;
theVector1->reserve(200*1024*1024);
theVector1->squeeze();
 
theVector2 = new QVector<int>;
theVector2->reserve(200*1024*1024);
 
delete theVector1;
delete theVector2;
хотя до theVector1->reserve - Mem Usage & VM Size < 10MB
после theVector1->reserve - Mem Usage & VM Size > 700MB
а после theVector1->squeeze- Mem Usage & VM Size снова < 10MB

Видно что squeeze освобождает память! Не могу понять прикола, в чем разница между этими двумя вариантами?
« Последнее редактирование: Сентябрь 14, 2009, 14:02 от Spectre » Записан
spectre71
Гость
« Ответ #11 : Сентябрь 14, 2009, 14:21 »

Как ни странно, но Igors прав! Это явный глюк QVector, осталось понять в чем он заключается.
Тест на моем классе проходит отличнно.
sbw::Indices - аналогичен QVector<int> (тоже список int, но без template, полностью своя реализация)

Код
C++ (Qt)
sbw::Indices* theVector1;
sbw::Indices* theVector2;
 
theVector1 = new sbw::Indices;
theVector1->maxCapacity(250*1024*1024);
theVector1->minCapacity();
 
theVector2 = new sbw::Indices;
theVector2->maxCapacity(250*1024*1024);
 
delete theVector1;
delete theVector2;
 
C Mem Usage & VM Size на соответствующих шагах все точно так же! Но без падения!
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Сентябрь 14, 2009, 14:29 »

А так если?
Winstrol, я Вас понял, но при этом теряется удобство/простота. Плюс для больших данных неизвестно хватит ли памяти для "переброски". Поэтому я себе соорудил велосипед из chunk'ов  Улыбающийся
Записан
SABROG
Гость
« Ответ #13 : Сентябрь 14, 2009, 14:34 »

Видно что squeeze освобождает память! Не могу понять прикола, в чем разница между этими двумя вариантами?

Разница похоже в squeeze, не срабатывает что ли. В первом случае первые 800Мб освобождает delete и второй вектор выделяет снова 800Мб. Во втором случае squeeze похоже ничего не делает в итоге идет попытка откушать память до 1600Мб.

Про squeeze() написано, что он освобождает память, которая не требуется для содержания элементов. Есть мысль, что через метод reserve() мы эту память делаем "нужной" для содержания элементов. Возможно нужно делать все-таки clean/erase + resize.
« Последнее редактирование: Сентябрь 14, 2009, 14:38 от SABROG » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Сентябрь 14, 2009, 14:37 »

Как ни странно, но Igors прав! Это явный глюк QVector, осталось понять в чем он заключается.
Из Ваших примеров я не могу понять почему я прав Улыбающийся

На Mac есть подлянка с ::realloc и т.к. Qt его активно использует...
Про Вындоуз не знаю.
Записан
Страниц: [1] 2 3 ... 7   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.198 секунд. Запросов: 23.