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

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

Страниц: 1 ... 4 5 [6] 7   Вниз
  Печать  
Автор Тема: QSqlQuery+QThread = bad_alloc  (Прочитано 43476 раз)
cdsmika
Гость
« Ответ #75 : Май 20, 2014, 08:33 »

Короче поток тут не причем
Скорее всего дело в append, как и говорили.
Код:
try
    {
        char * d = new char[1700000000];

        for (int i= 0; i < 1700000000- 1; ++i)
        {
            d[i] = 1;
        }
        delete[] d;
    }
    catch(std::bad_alloc)
    {
        qDebug() << "bad_alloc";
    }
все круто
Код:
try
    {
        QString l;

        while (l.length() < 300000000)
        {
            l.append("111111");
        }
    }
    catch(std::bad_alloc)
    {
        qDebug() << "bad_alloc";
    }
песта ((( QSqlQuery::value дает тот же результат - падает с bad_alloc

Код:
        while (l.length() < 300000000)
        {
            l.append("111111");
        }
Можно примерно подсчитать во сколько нам обойдется такой цикл:
"111111" = 12 байт
300000000 * 12 = 3600000000 байт = 3515625 кбайт = 3433,2275390625 мбайт = 3,35276126861572265625 гбайт
Если памяти будет не хватать, новую нельзя выделять

У вас оперативной памяти то хватит? Улыбающийся
зачем умножать 12 на 300000000 я не понял. там же по размеру
Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #76 : Май 20, 2014, 09:34 »

Цитировать
зачем умножать 12 на 300000000 я не понял. там же по размеру
Уже ответил, что ошибся Улыбающийся
Записан

cdsmika
Гость
« Ответ #77 : Август 23, 2014, 01:42 »

Кому интересно вот в чем дело:
http://www.rsdn.ru/forum/cpp/913085.flat
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #78 : Август 23, 2014, 09:33 »

Кому интересно вот в чем дело:
http://www.rsdn.ru/forum/cpp/913085.flat
В чем дело было описано на первой же страницы этой темы.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #79 : Август 23, 2014, 09:49 »

В чем дело было описано на первой же страницы этой темы.
Открыл, но  так и не понял где  Улыбающийся

Код:
while (l.length() < 300000000)
{
    l.append("111111");
}
Блок памяти слишком велик. 600 метров "чистого" + какой-то пул QString, вполне возможно всего около 1 Gb. Не все ОС могут выделять блок такого размера, даже если памяти хватает физически. Неск лет назад боролся с этой проблемой, пришел к выводу что хватать большие блоки - себе дороже, переделал на чанки, все проблемы исчезли.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #80 : Август 23, 2014, 09:59 »

Открыл, но  так и не понял где  Улыбающийся
В посте m_ax, где он пишет о фрагментации адресного пространства.

Неск лет назад боролся с этой проблемой, пришел к выводу что хватать большие блоки - себе дороже, переделал на чанки, все проблемы исчезли.
Фрагментировать память процесса (а точнее адресное пространство) можно и начиная с маленьких блоков, просто с большими блоками эффект проявляется быстрее.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #81 : Август 23, 2014, 11:02 »

Фрагментировать память процесса (а точнее адресное пространство) можно и начиная с маленьких блоков, просто с большими блоками эффект проявляется быстрее.
Память выделяется страницами (обычно по 4K) которые выгружаются/подгружаются. Не знаю как можно  убить этот механизм дефрагментацией, надо сильно постараться. Выделение сводится к ф-ции типа vm_alloc которая уже собственно выделяет страницы, и, насколько я знаю, резервирует для них непрерывное дисковое пр-во. Тут да, могут быть проблемы.

Ну а чисто практически все сводится к банальной рекомендации "не хватайте слишком большие блоки, храните по частям (не переломитесь)"
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #82 : Август 23, 2014, 11:49 »

Память выделяется страницами (обычно по 4K) которые выгружаются/подгружаются. Не знаю как можно  убить этот механизм дефрагментацией, надо сильно постараться. Выделение сводится к ф-ции типа vm_alloc которая уже собственно выделяет страницы, и, насколько я знаю, резервирует для них непрерывное дисковое пр-во. Тут да, могут быть проблемы.
Вы сейчас выдали все, что когда то слышали о менеджерах памяти, причем обо всех. Улыбающийся
Со страницами работает менеджер памяти ОС, который к менеджеру памяти из libc (который и реализует malloc/free) не имеет никакого отношения. Это два совершенно разных механизма, не смотря на то что последний иногда пользуется первым.
Да и проблема не в самой памяти (физической может быть хоть 100500Gb), а в фрагментации адресного пространства. На 32 битах это делается легко даже не большими блоками, как в вышеописанном примере. Главное, что бы последующий выделяемый блок был больше предыдущего.

Ну а чисто практически все сводится к банальной рекомендации "не хватайте слишком большие блоки, храните по частям (не переломитесь)"
Пример из этой темы показывает обратное, что фрагментировать можно и маленькими блоками.
« Последнее редактирование: Август 23, 2014, 12:40 от Old » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #83 : Август 23, 2014, 13:59 »

Со страницами работает менеджер памяти ОС, который к менеджеру памяти из libc (который и реализует malloc/free) не имеет никакого отношения. Это два совершенно разных механизма, не смотря на то что последний иногда пользуется первым.
Растущая QString требует один/непрерывный блок памяти, поэтому дело упрется в выделение страниц, на подробности malloc можно не обращать внимания.

Пример из этой темы показывает обратное, что фрагментировать можно и маленькими блоками.
Не увидел такого

Вы сейчас выдали все, что когда то слышали о менеджерах памяти, причем обо всех. Улыбающийся
Не слышал, а изучил на своем опыте. Почему надо обязательно фыркнуть в лицо собеседнику? Что этим достигается? Только то что что пропадает всякое желание разговаривать со спесивым дустовцем  Улыбающийся 
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #84 : Август 23, 2014, 14:09 »

Растущая QString требует один/непрерывный блок памяти, поэтому дело упрется в выделение страниц, на подробности malloc можно не обращать внимания.
Это просто набор слов, ничего не означающих. Уж простите, но это говорит о том, что вы не очень понимаете о чем говорите. Улыбающийся
Еще раз простите, а то вы опять решите, что я фыркаю. Улыбающийся
Найдите компьютер где много памяти, например, гигов 8 или более. Соберите 32 битное приложение с указанным в теме куском кода и запустите его. Вы удивитесь, но оно завершиться с сообщением об нехватки памяти. Но мы то знаем, что на машине 8 или даже больше гигабайт физической памяти. Так что же произошло? Каких страниц где не хватило? А ведь есть еще своп. Улыбающийся

Не увидел такого
Сожалею. На самом деле там все очень просто, и я легко могу рассказать об этих процессах на пальцах. Только вам это не надо, для "работы" вам достаточно "якобы правильных" мифов:
Ну а чисто практически все сводится к банальной рекомендации "не хватайте слишком большие блоки, храните по частям (не переломитесь)"

Не слышал, а изучил на своем опыте.
Скорее всего поэтому вы не понимаете, что же происходит на самом деле и в чем причина происходящего.
Поэтому, как древние люди наблюдающие за молнией, решили для непознанного придумать мифы.
Ну что же - пожалуйста. Улыбающийся

« Последнее редактирование: Август 23, 2014, 14:23 от Old » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #85 : Август 23, 2014, 17:22 »

Вот маленькая демонстрация:
Код
C++ (Qt)
#include <iostream>
#include <QVector>
 
using namespace std;
 
int main()
{
       {
               cerr << "Allocate 1Gb" << endl;
               QVector<char> tst( 1024 * 1024 * 1024 );
       }
       {
               cerr << "Allocate..." << endl;
               size_t it = 0;
 
               QVector<char> vec;
               QVector<char> chunk( 1024 * 1024 );
               for(;;)
               {
                       vec += chunk;
                       cerr << it++ << " Mb" << endl;
               }
       }
}
 

Из 32 битных ОС у меня есть венда в virtualbox, под ней я могу спокойно выделить буфер в 1Гб (первый вектор), а вот во втором случае с выделением в цикле кусками по 1 Мб, у меня выделяет в общей сложности 510 Мб.
Чего же перестало хватать? Вот же, доли секунды назад был гиг (на самом деле под два), а сейчас всего 510 Мб? Куда там страницы делись? Улыбающийся
Записан
Nidxogg
Гость
« Ответ #86 : Август 23, 2014, 17:51 »

Ну так и как с этим бороться?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #87 : Август 23, 2014, 20:01 »

Ну так и как с этим бороться?
Тут зависит на каком уровне вы хотите с этим разобраться.
Если на уровне мифов и легенд, то достаточно:
Ну а чисто практически все сводится к банальной рекомендации "не хватайте слишком большие блоки, храните по частям (не переломитесь)"
Точнее, на 32 битных платформах нужно очень тщательно продумывать выделения больших непрерывных участков памяти. Например, под вендой вы захватываете буфер в 500 Мб, вот расширить его до 1 Гб в два этапа по 250 Мб (вначале до 750 Мб, а потом до 1 Гб) у вас не получиться, хотя памяти для небольших блоков будет в избытке.

Или переходом на 64 битную платформу. Там проблемы с адресном пространством не возникнут еще долго, в связи с огромных его объемом. Хотя мы помним высказывание одного идиота о том, что 640 Кб хватит всем. Поэтому, лучше с памятью и адресным пространством разобраться один раз.

Если будут вопросы пишите, попробую простым языком объяснить, что же там происходит с памятью.

Записан
Nidxogg
Гость
« Ответ #88 : Август 23, 2014, 20:29 »

Цитировать
Если будут вопросы пишите, попробую простым языком объяснить, что же там происходит с памятью.
Было бы интересно прочитать.

P.S Если в программе постоянно выделяется/освобождается память блоками по 3-5 мб, данная проблема с фрагментацией тоже будет иметь место?
Непрерывное время работы программы порядка пары недель.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #89 : Август 24, 2014, 07:43 »

Было бы интересно прочитать.
Давайте рассмотрим проблему фрагментации адресного пространства на микропроцессоре, который может адресовать только 64 байта памяти.
Все сказанное будет справедливо и для любого другого процессора, зато рисовать карту памяти процесса будет проще. Улыбающийся

Это я нарисовал пустую карту памяти процесса:
[................................................................]

Загружаем в нее код и данные процесса, а так же добавляем стек и мапим код ядра:
[CCCCCCCCCCCDDDD...................................SSSKKKKKKKKKKK]

Здесь:
  с 00 по 10 байт хранится код программы
  с 11 по 14 байт данные программы
  c 15 по 49 байт свободная область памяти
  с 50 по 53 байт стек процесса
  с 54 по 63 байт ядро
  
Область для расположения кучи располагается с 15 байта и заканчивается на 49.

Давайте выделим блок памяти в 5 байт:
[CCCCCCCCCCCDDDDAAAAA..............................SSSKKKKKKKKKKK]

Менеджер памяти нам вернет указатель на 15 байт и зарезервирует 5 байт в куче.

Теперь мы хотим добавить к нашему блоку еще 3 байта, делается это в несколько этапов:
Вначале мы захватывает новый блок памяти с необходимым размером (5 байт + 3 байта = 8 байт):
[CCCCCCCCCCCDDDDAAAAABBBBBBBB......................SSSKKKKKKKKKKK]

Затем мы копируем в новый блок данные из строго и освобождаем последний:
[CCCCCCCCCCCDDDD.....BBBBBBBB......................SSSKKKKKKKKKKK]

Указатель на данные у нас уже указывает на 20 байт памяти.

Повторяем процесс еще раз:
[CCCCCCCCCCCDDDD.............CCCCCCCCCCC...........SSSKKKKKKKKKKK]

Все. Больше расширить блок на очередные 3 байта мы не сможем, хотя свободной памяти еще много.
Небольшие блоки будут выделяться легко, а вот большой непрерывный участок вызовет нехватку памяти.

Было бы не плохо уметь двигать блоки, но в C/C++ это не возможно, т.к. указатель это реальный адрес в адресном пространстве процесса и если переместить блок, то указатели станут не валидными.

Освободившиеся блоки памяти не всегда могут объединится в один большой блок, например, между ними может быть выделен небольшой блок, который не будет освобожден.
[CCCCCCCCCCCDDDD.....X..Y....CCCCCCCCCCC...........SSSKKKKKKKKKKK]
« Последнее редактирование: Август 24, 2014, 07:59 от Old » Записан
Страниц: 1 ... 4 5 [6] 7   Вверх
  Печать  
 
Перейти в:  


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