Разбор нескольких файлов (по одному) с быстрым XML, чтобы использовать меньше памяти - PullRequest
0 голосов
/ 16 января 2020

Мне нужно прочитать большой XML файл (~ 5,4 ГБ). Я заметил, что при анализе файла с быстрым XML используется примерно в 6 раз больше оперативной памяти, чем размер файла на диске (поэтому для анализа файла размером 200 МБ требуется ~ 1,2 ГБ ОЗУ, а для файла 5,4 ГБ потребуется ~ 32,4 ГБ ОЗУ !). Чтобы избежать обмена, я решил разделить файл на более мелкие куски и прочитать их по одному (используя инструмент xml -split из библиотеки запятая ). Я могу правильно читать и анализировать файлы XML.

Проблема: Когда я достигаю конца первого файла, я могу успешно открыть второй, но первый файл все еще использует памяти, даже если я очищаю rapidxml::document и / или удаляю rapidxml::file<>. Вот заголовочный файл:

//*1st code snippet*
//.h file
#include "rapidxml_utils.hpp"        //Implicitly includes 'rapidxml.hpp'
...
private:
  std::basic_ifstream<char> inStream;
  rapidxml::file<>* sumoXmlFile;
  rapidxml::xml_document<> doc;
  uint16_t fcdFileIndex;               //initialized at 0
...

Вот код для открытия нового XML файла:

//*2nd code snippet*
//.cc file
bool parseNextFile()
{
  //check if file exists (filenames are : fcd0.xml, fcd1.xml, fcd2.xml, etc.)
  struct stat buffer;
  std::string fileName = std::string("fcd") + std::to_string(fcdFileIndex) + ".xml";
  bool fileExists = (stat(fileName.c_str(), &buffer) == 0);

  if(!fileExists)
    return false;

  //"increment" the name for the next file (when this method will be recalled)
  fcdFileIndex++;

  //open a reading stream, create the 'file' and parse it
  inStream.open(fileName.c_str(), std::basic_ifstream<char>::in);
  sumoXmlFile = new rapidxml::file<>(inStream);
  doc.parse<0>(sumoXmlFile->data());

  return true;
}

Я вызываю parseNextFile() в коде в первый раз (для откройте 1-й файл). Затем регулярно вызывается метод update():

//*3rd code snippet*
void update()
{
  //Read next tag
  rapidxml::xml_node<>* node = doc.first_node("timestep");

  //If no 'timestep' tags are left, clean and parse the next file.
  if(!node)
  {
    doc.clear();         //**not sure**
    delete sumoXmlFile;  //**not sure**
    inStream.close();    //**not sure**

    if(parseNextFile())  //See 2nd code snippet
      node = doc.first_node("timestep");
    else
      return;
  }

  //read the children nodes of the current 'timestep'
  for(rapidxml::xml_node<>* veh = node->first_node(); veh; veh = node->first_node())
  {
    ...
    //read some attributes using 'veh->first_attribute("...")'
    ...

    node->remove_first_node();
  }

  doc.remove_first_node();
}

Проблема заключается в (я думаю) при «очистке» (строки, помеченные как «не уверен» в предыдущем фрагменте кода). Я пробовал несколько комбинаций clear(), delete, вызывая деструктор memory_pool. Ничто из того, что я пробовал, не освобождает память. Я также непосредственно открыл XML файлы с помощью

sumoXmlFile = new rapidxml::file<>(fileName.c_str()); //see 2nd code snippet

вместо создания ifstream вручную.

Для суммирования при открытии первого XML файл, он успешно загружается и используется некоторая память. Когда я закончу с этим, я пытаюсь очистить / удалить / очистить пул памяти (без успеха) и открыть второй файл (с успехом). На этом этапе 1-й и 2-й файлы используют память. Разбор 2-го файла работает правильно (даже 3-й, 4-й и т. Д.), Но в какой-то момент ОЗУ становится довольно полным.

(наконец) Мой вопрос: Я что-то сделал неправильно освобождать память, используемую первым файлом? Можно ли освободить используемую память и прочитать следующий файл? Я не против уничтожить файлы XML в процессе, если это необходимо.

(Ради полноты: этот код на самом деле представляет собой OMNeT ++ симуляцию и файл XML генерируется SUMO . Я уверен, что файл XML не содержит ошибок.)

Спасибо за любую помощь или советы, которые могут быть предоставлены!

...