Конференция "Основная" » Поиск утечки памяти и TXMLDocument
 
  • Eraser © (21.02.17 04:32) [0]
    Привет, товарищи.
    Который день пытаюсь побороть/найти утечку памяти, связанную с использованием TXMLDocument.

    Вот тестовый код:
    class procedure TTestXmlThread.ProcessTest;
    const
     MY_XML_ENCODING = 'UTF-8';
    var
     XMLDoc: IXMLDocument;
     RootNode: IXMLNode;
     XmlRootName: string;
     Version: Integer;
     msData: TMemoryStream;
    begin
     XmlRootName := 'test_root_node' + Random(MaxInt).ToString;
     Version := Random(MaxInt);

     msData := TMemoryStream.Create;
     XMLDoc := TXMLDocument.Create(nil);
     try
       //(XMLDoc as TXMLDocument).DOMVendor := DOMVendors.Find('Omni XML');

       // Инициализируем XML-документ.
       XMLDoc.LoadFromXML('<?xml version="1.0"?><' +
         XmlRootName + ' version="' +
         Version.ToString +'"></' +
         XmlRootName + '>');

       XMLDoc.Encoding := MY_XML_ENCODING;

       // Формируем XML.
       RootNode := XMLDoc.DocumentElement;

       //SerializeToNode(RootNode);

       msData.Size := 0;
       XMLDoc.SaveToStream(msData);

       OutputDebugString(PChar(XmlRootName));
     finally
       XMLDoc := nil;
       FreeAndNil(msData);
     end;
    end;


    Вот ссылка на тестовый пример https://dl.dropboxusercontent.com/u/26403307/XMLMemLeak.zip (в архиве исходник проекта с примером и подключенный к нему свежий FastMM). Важно! В настройках FastMM включена опция {$define AlwaysClearFreedMemory}, это гарантирует принудительное затирание нулями всех освобождаемых блоков памяти.

    Суть проблемы вот в чем - если выполнить данный код, то в выделенной памяти приложения остаются фрагменты, выглядящие примерно вот так https://dl.dropboxusercontent.com/u/26403307/xmlmemleak.png

    (Отдельной строкой безмерная благодарность Rouse_ за удобную утилиту processmm)

    Стройки в памяти связанны именно с TXMLDocument. При этом, объект TXMLDocument, который реализует интерфейс IXMLDocument, конечно же, освобождается, его деструктор и деструкторы вложенных нодов срабатывают.

    В крупном проекте это выглядит так, - процесс постепенно разрастается (private memory) и, по всей видимости, менеджер памяти начинает заметно тормозить, вплоть до полной деградации. Причем, AV и других нарушений памяти нет. FastMM об утечках памяти не рапортует.

    Еще одно замечание, проблема воспроизводится не только на движке MSXML, но и на других тоже (например, Omni XML). Т.е., наверное, дело в абстракции TXMLDocument, только вот не ясно где именно.

    Честно гуглил - в таком криминале TXMLDocument не был замечен.
  • rrrrr © (21.02.17 08:59) [1]
    а если TXMLDocument.Create(something_not_nil) + Free ?
  • DayGaykin © (21.02.17 13:59) [2]
    А reportmemoryleaksonshutdown :=  true что говорит?

    Память при освобождении из кучи наверняка не затирается, твоя находка ни о чем не говорит.
  • Eraser © (21.02.17 16:03) [3]

    > rrrrr ©   (21.02.17 08:59) [1]

    это может привести и приведет к AV в высоконагруженном многопоточном приложении.

    > something_not_nil

    destructor TXMLDocument.Destroy;
    begin
     Destroying;
     if FOwnerIsComponent and Active and Assigned(FDocumentNode) and (FRefCount > 1) then
       (FDocumentNode as IXMLNodeAccess).ClearDocumentRef;
     SetActive(False);
     FreeAndNil(FXMLStrings);
     inherited;
    end;

    поведение изменится только, если Owner - именно компонент, а это не годится для многопоточного приложения. поэтому не пробовал.


    > DayGaykin ©   (21.02.17 13:59) [2]
    > А reportmemoryleaksonshutdown :=  true что говорит?

    молчание.

    что примечательно - если запустить данный код в цикле, естественно, никакой утечки нет. до последнего надеюсь, что это все таки ошибка в 17 строке моего приложения. но, прежде чем писать сюда, я больше недели с переменным успехом пытался найти эту утечку. буду пробовать сторонний парсер, а там посмотрим.
  • rrrrr © (21.02.17 16:33) [4]
    это может привести и приведет к AV в высоконагруженном многопоточном приложении.


    это не может ни к чему привести.

    txmldocument хитрый класс.

    Create(nil) = ведет себя как интерфейсная ссылка, free делать нельзя.
    Create(owner) = ведет себя как чистый потомок TObject, деструктор вызываешь сам.
  • rrrrr © (21.02.17 16:37) [5]
    а вообще txmldocument - для школьников.

    uses msxml2_tlb
    CoDomDocument.create
  • Eraser © (21.02.17 16:51) [6]

    > rrrrr ©   (21.02.17 16:33) [4]


    > uses msxml2_tlb

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


    > Create(owner) = ведет себя как чистый потомок TObject, деструктор
    > вызываешь сам.

    не TObject, а TComponent, там есть разница, нужна защита создания тогда, буду пробовать.
  • Eraser © (22.02.17 13:45) [7]
    Прикрутил самописный менеджер памяти в виде прямой обертки над heap. Рост потребления заметно уменьшился. Скорее всего, все таки, проблема не в утечке памяти, а в жесткой фрагментации. Надо будет еще попробовать msvcrt.
  • Rouse_ © (22.02.17 17:17) [8]
    Здесь нет утечки, это чистая фрагментация памяти.
    Технически можно избежать подменяя менеджер своим именно на работе с документом (тебе ж только указатель нужен) но хлопотно, я так в одном из проектов делал - умаялся с отладкой
  • Eraser © (22.02.17 23:26) [9]

    > Rouse_ ©   (22.02.17 17:17) [8]

    задумываюсь над тем, чтобы парсинг/сериализацию XML (а память "утекает", по всей видимости, через строки, в основном, ну и через instance'ы сопричастных объектов) разместить в отдельном утилитарном процессе (который можно смело рестартовать или запускать несколько копий), и скармливать этому процессу через IPC данные для парсинга, но там есть много НО.

    плохо даже не то, что память отъедается, физически ее более чем достаточно, плохо что 64 битный процесс уже при 2-2.5 Гб начинает сильно тормозить обработку данных на простейших операциях, где нужно выделить/освободить память, очевидно, потому что разрастаются таблицы или деревья или что там используется в менеджере памяти.

    на чистой heap мне пока нравится как работает, но нужно время на тесты.

    PS
    вот после 12 часов работы натравил ProcessMM на свой процесс с менеджером памяти на куче, который в занимает жалких 1,5 Гб на данный момент. processmm64.exe отожрал 10 Гб ОЗУ и, видимо, подвис. Подождал его минуты 2. обычно, процесс с таким объемом памяти ProcessMM открывает за пару тройку секунд. это говорит о том, что эти 1,5 Гб - мельчайшие фрагменты в миллионах нодов кучи.

    PPS
    все таки надо будет протестировать майкросовтовский msvcrt.
  • Eraser © (22.02.17 23:29) [10]

    > Rouse_ ©   (22.02.17 17:17) [8]

    кстати, вопрос. если создать несколько heap - менеджер памяти windows будет размещать их более-менее отдельными блоками, хотя бы в отдельных страницах, либо это чисто логическое разделение и все будет вместе?
  • Rouse_ © (23.02.17 00:01) [11]
    Если так сильно завис - очень жесткая дефрагментация (с учетом что 10 гектаров отьел), а по второму вопросу, нет там аллоцируется постранично и он пытается в рамках нее все раскидать, ну и выделяет новые при нехватке
  • Rouse_ © (23.02.17 12:59) [12]
    ЗЫ: вот обрати внимание, я там специально их группами выделял: https://dl.dropboxusercontent.com/u/70911765/heap.png

    вот а еще, зайди в настройки и сними галку "Show detailed heap" - это достаточно тяжелая операция, вероятно на ней и подвис
  • Eraser © (23.02.17 14:32) [13]

    > Rouse_ ©   (23.02.17 12:59) [12]


    > сними галку "Show detailed heap"

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

    но пересматривать архитектуру все равно придется, т.к. число пользователей медленно, но неумолимо растет.
  • Rouse_ © (23.02.17 14:38) [14]
    Так у тебя еще и сервер? Конечно пересматривать нужно, у меня сервера годами работают, не шучу
  • Eraser © (23.02.17 15:55) [15]

    > Rouse_ ©   (23.02.17 14:38) [14]

    да, там около 100000 tcp соединений, периодически с некоторыми идет обмен сообщениями на базе xml. но сам транспорт хорошо закэширован, а вот с XML и с тем, что связано со строками беда.
    до поры до времени все тоже работало, если не годами, то месяцами, остановки были только по причине апдейта системы или самого ПО. однако с ростом нагрузки появилась обозначенная проблема.
  • Rouse_ © (23.02.17 16:29) [16]
    слушай, а свяжись ка ты с женькой jack128, в понедельник могу состыковать. Он у нас с этой проблемой маялся в свое время и в итоге накидал какой-то простенький класс (банально с MSDN скомуниздил) там быстрая загрузка XML вроде бы даже без построения DOM.
  • Rouse_ © (23.02.17 16:34) [17]
    Я конечно не могу полностью гарантировать что это то что нужно - у нас с ним разные направления, но что-то подобное он решал, поэтому если я ошибся - не обессудь :)
  • Eraser © (24.02.17 03:05) [18]

    > Rouse_ ©   (23.02.17 16:29) [16]

    благодарю за наводку, уточню.

    а есть какая-нибудь проверенная информация по поводу Segment Heap?

    https://www.blackhat.com/docs/us-16/materials/us-16-Yason-Windows-10-Segment-Heap-Internals-wp.pdf
  • Rouse_ © (07.03.17 15:38) [19]
    Только сейчас обратил внимание что ты спрашивал, а зачем тебе это надо?
    Я сильно кучей не занимался, но общей информацией в принципе владею (на практике никогда правда не нужна она была).

    ЗЫ: кстати обнови утилитку, я там добавил кучу удобностей (мне как раз по работе для разбора качества работы ВМ потребовалось), дизасм стал выглядеть гораздо удобней и проще для анализа (он теперь отладочные МАР кушает в легкую + реконнект к процессу сделал ну и работа с GUI гораздо ускорилась для поиска проблемы):
    https://github.com/AlexanderBagel/ProcessMemoryMap/raw/master/img/10.png
    https://github.com/AlexanderBagel/ProcessMemoryMap/raw/master/img/11.png
    Релиз тут: http://rouse.drkb.ru/winapi.php#pmm2
  • Eraser © (10.03.17 11:30) [20]

    > Rouse_ ©   (07.03.17 15:38) [19]


    > Только сейчас обратил внимание что ты спрашивал, а зачем
    > тебе это надо?

    Дело в том, что сервера одинаковой конфигурации, но на разных ОС ведут себя несколько по разному. на 2012 проблем нет практически вообще (хотя разрастание памяти тоже имеет место быть), тогда как на 2008 они обозначены в данной ветке.
 
Конференция "Основная" » Поиск утечки памяти и TXMLDocument
Есть новые Нет новых   [118640   +43][b:0][p:0.001]