Конференция "Начинающим" » Ошибка Out of memory при загрузке файла в TStringList
 
  • Pcrepair © (13.12.17 23:14) [0]
    Добрый день. Есть следующая ситуация
    РС(i7 8Gb Win7 x64 + RAD XE3), приложения можно компилировать только в 32 разр. режиме
    - список грузит файл с диска

    Procedure RestorData;
    begin
     try
       CS.Enter;
       try
         gStore.LoadFromFile(ExtractFilePath(Application.ExeName)+'Store.txt');
       finally
         CS.Leave;
       end;
     except
       on E:Exception do
       begin
         ShowMessage('RestorDataParams = '+'('+E.Message+')');
       end;
     end;
    end;


    - при определенных условиях(не всегда) выскакивает ошибка:
    First chance exception at $7561C54F. Exception class EOutOfMemory with message 'Out of memory'. Process loader.exe (3736)
    в основном ошибка выскакивает при попытке загрузить в список файл размером в 300 мб с числом строк около 3 млн. при запуске программы,
    или выгрузить список обратно при выходе из программы.
    - список со строками совершенно необходим(стек со списком УРЛ для загрузки), хотя...

    Вопросы :
    1. вообще эта проблема решаема для TStringList
    2. если список не тянет, что еще можно использовать для загрузки-выгрузки милионов строк(до 500 символов в строке) из какого либо хранилища на ЖД



  • kilkennycat © (14.12.17 10:44) [1]
    1. да.
    2. TStringList

    TStringList служит для отображения. отобразить он может лишь столько, сколько мониторов у компа. Остальное храните там, где оно уже хранится.
  • Pcrepair © (14.12.17 10:52) [2]
    с листбокс не перепутал? для отображения ахаха
  • KilkennyCat © (14.12.17 11:08) [3]
    нет, перепутал с вариантом ответить или нет. надо было не отвечать.
  • Sha © (14.12.17 12:37) [4]
    > список со строками совершенно необходим(стек со списком УРЛ для загрузки)

    Предполагается ли затем все эти УРЛ также одновременно загрузить?
    Просто вопрос.
  • han_malign © (14.12.17 12:54) [5]

    > (стек со списком УРЛ для загрузки)

    - при условии последовательного доступа к элементам списка - проще хранить единым блоком с строке и парсить на лету...
    Либо отдельно построить список смещений. Либо честный связный список...

    Проблема древняя как мир
    LoadFromFile():
    1. Файл целиком загружается в строку.
    2. SetTextStr()
    - где на каждом элементе происходит выделение памяти под очередную подстроку и перевыделение памяти под очередной размер списка.
    То есть на определённом этапе у нас
    - выделена память под все содержимое файла
    - выделена память под N-подстрок
    - выделена память под array[N] of TStringItem
    а нам надо выделить память под array[N+N div 4] of TStringItem, т. к. N-подстрок с большой долей вероятности фрагментируют память - и расширение блока памяти на месте невозможно.
    (...|array[n]|...substr[N-1]|)

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

    Если заранее знать количество строк - проблему можно временно решить
    gStore.Capacity:= MaxN;


    - если (<размер фала> * 2 + O(N) + MaxN * sizeof(TStringItem)) - не вылезает за размер доступной памяти.
    O(N) - оверхэд на хранение N строк(TStrRec + списки менеджера памяти).


    > для загрузки-выгрузки

    TMemoryStream.LoadFromFile();
    parse_and_do_something(PChar(TMemoryStream.Memory), TMemoryStream.Size);
  • Pcrepair © (14.12.17 16:15) [6]

    > Предполагается ли затем все эти УРЛ также одновременно загрузить?

    предполагается, но не одновременно а поочередно, причем выборка текущего УРЛ через РандомРеиндж

    пока что использование АссасинФайл вполне помогло в деле загрузки 3млн. строк из текстового файла в переменную(список). правда грузится подольше, но это не принципиально
  • Sha © (14.12.17 21:19) [7]
    В таком случае непонятно, зачем грузить строки.

    Можно держать их в любой БД или сортированном файле.
  • han_malign © (15.12.17 08:49) [8]

    >  или сортированном файле

    - проблема не в сортировке, а в равномерном распределении РандомРеиндж по элементам. Если делать случайную выборку по полному размеру файла - вероятность попадания будет зависеть от длины URL(в сравненнии с количеством элементов - перекос мизерный, но лучше избегать математических ловушек, т.к. если отсортировать элементы по длине - получим явно выраженную линейную функцию распределения)... То есть, нужно либо нормализовать длину строки, либо строить индекс смещений. Если нужна выборка с отсечением дублей - однозначно индекс, который можно рэндомизировать при построении, а потом делать прямой обход.
    З.Ы. Главное не удивляться, что случайный список всегда получется одинаковый, при одинаковом начальном RandSeed. :)

    >  держать их в любой БД

    - я так полагаю - список URL быстро устаревает, и скорее всего периодически генерируется какой-то третьей стороной в самом элементарном виде, и БД превратится в run-time прослойку(тот самый микроскоп)...
    Хотя уже замечал тенденцию использовать LiteSQL в роли универсального контейнера...
  • Sha © (15.12.17 09:40) [9]
    > проблема не в сортировке, а в равномерном распределении РандомРеиндж

    я даже не догадываюсь, что такое этот ваш РандомРеиндж,
    но если это то, что я думаю, то можно отсортировать по нему
    и просто читать файл последовательно-закольцовано ))
 
Конференция "Начинающим" » Ошибка Out of memory при загрузке файла в TStringList
Есть новые Нет новых   [118630   +21][b:0][p:0.001]