CrossTab System.OutOfMemory

Обсуждение Stimulsoft Reports.Net
Леонид
Сообщения: 328
Зарегистрирован: 23 июл 2009, 05:53

CrossTab System.OutOfMemory

Сообщение Леонид » 22 апр 2015, 13:35

Добрый день!

Столкнулись с проблемой больших данных в кростабе.
Суть проблемы: запускаем отчёт - получается System.OutOfMemory. Если не получаем в первый раз, то при втором запуске 100%.
Конкретно наш пример во вложении с данными. Данные выбраны из базы с 01.04.2015 по 22.04.2015. Однако, пользователям необходимо выбирать данные за несколько месяцев. В результате на данный момент пользователи не могут вывести необходимые данные.

Версия Стимула 2012.1.1300.0. Но не спешите рекомендовать последнюю версию, мы пробовали запускать на 2014.3.0.0, - результат тот же.
Вложения
test_report.7z
(896.11 КБ) 133 скачивания
HighAley
Сообщения: 1975
Зарегистрирован: 08 июн 2011, 07:36

Re: CrossTab System.OutOfMemory

Сообщение HighAley » 23 апр 2015, 11:37

Здравствуйте.

Ваш отчёт с присланными данными строится бел ошибок. Нам необходима дополнительная информация. Как загружается отчёт, как строится первый и второй раз.
Пришлите, пожалуйста, простой проект, который воспроизводит вашу ситуацию.

Спасибо.
Леонид
Сообщения: 328
Зарегистрирован: 23 июл 2009, 05:53

Re: CrossTab System.OutOfMemory

Сообщение Леонид » 23 апр 2015, 13:12

Добрый день!

Очень просто, возьмите редактор "C:\Program Files\Stimulsoft Reports.Net 2014.3\Bin\Designer.exe", откройте "Отчёт.mrt", загрузите "data.xml", нажмите Preview. Всё работает, да, но это первый раз. Теперь перейдите на Вкладку Page1, и теперь снова запустите отчёт, нажав Preview - у нас выдаёт OutOfMemory уже на второй раз. А если данных больше (скажем, взять data.xml из архива, и скопировать все её строки, чтобы данных стало в два раза больше), то и на первый.

Мы провели дополнительные тесты. И вот, что выяснили. При использовании метода Render() в SDI приложении (на тестовом примере) - всё работает, однако в MDI приложении не работает.

Код тестового приложения, в котором работает:

Код: Выделить всё

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Stimulsoft.Report;

namespace StiCrossTabTest
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    // stimul objects
    private Stimulsoft.Report.StiReport stiReport = null;
    private Stimulsoft.Report.Viewer.StiViewerControl stiPreview = null; // public, to change properties in needed reports

    DataSet dsData = new DataSet();
    DataTable dtData = new DataTable("qrMain");

    private void button1_Click(object sender, EventArgs e)
    {
      button1.Hide();

      if (stiReport == null)
      {
        stiReport = new StiReport();

        stiPreview = new Stimulsoft.Report.Viewer.StiViewerControl()
        {
          Dock = DockStyle.Fill,
          Visible = true
        };

        // preview control events
        stiPreview.Close += new EventHandler(stiPreview_Close); // handle Close button event

        // assign report object to preview control
        stiPreview.Report = stiReport;
        stiPreview.FirstPage();
        stiPreview.SetZoom(100);

        stiReport.PreviewSettings = (int)stiPreview.PreviewSettings; // здесь этот код работает, т.к. стоит до медода .Render()

        // assign report object to preview control //
        stiPreview.Report = stiReport; // set report object for preview control (each time to refresh the view)
        stiPreview.Visible = true; // make preview control visible
        stiPreview.FirstPage(); // set report to the first page
        stiPreview.SetZoom(100); // set it 100 percent

        // add viewer to the form
        this.Controls.Add(stiPreview);
      }

      stiReport.Load("Отчёт.mrt"); // load report each time (just like we get it from Oracle blob)

      dsData.ReadXml("data.xml"); // load data each time (just like we get it from Oracle data)
      stiReport.RegData(dsData);
      stiReport.Dictionary.Synchronize();

      stiReport.Render();
    }

    // close button of the preview control
    private void stiPreview_Close(object sender, EventArgs e)
    {
      if (!button1.Visible)
        button1.Show();
    }

  }
}
Этот же код, но в MDI приложении почему-то не работает, тоже выдаёт OutOfMemory. Оговорюсь, что проводили тесты на i7 с 18 Gb RAM, так что памяти навалом, а data.xml всего 44 Mb.
Леонид
Сообщения: 328
Зарегистрирован: 23 июл 2009, 05:53

Re: CrossTab System.OutOfMemory

Сообщение Леонид » 24 апр 2015, 08:45

Добрый день!

Сгенерировал тестовый проект с данными. На форме кнопка "Run", если её нажать, загрузится xml с данными, выведет отчёт. Потом надо нажать Close в очёте, появится снова кнопка "Run", нажать её ещё раз, - в этот раз на методе .Render() будет Exception.
Собственно, если данных будет больше, Exception будет и в первый раз.
Вложения
StiCrossTabTest2.7z
(795.84 КБ) 136 скачиваний
HighAley
Сообщения: 1975
Зарегистрирован: 08 июн 2011, 07:36

Re: CrossTab System.OutOfMemory

Сообщение HighAley » 25 апр 2015, 05:55

Здравствуйте.

Вы нам прислали SDI проект. Мы не можем на нём воспроизвести проблему.
С присланным отчётом проект вообще отказался работать, тестировали с предыдущим.
Пришлите, пожалуйста, рабочий проект, который воспроизводит проблему.

Спасибо.
Леонид
Сообщения: 328
Зарегистрирован: 23 июл 2009, 05:53

Re: CrossTab System.OutOfMemory

Сообщение Леонид » 27 апр 2015, 08:21

Доброе утро!

Да, верно, это SDI приложение, т.к. мы не можем в точности воспроизвести вам пример MDI приложения, т.к. оно технически сложное и использует сторонние компоненты.

Однако, мы провели дополнительные тесты, и удалось получить тот же Exception на отдельном простейшем SDI приложении (см. вложение).

Суть та же: компилируем, запускаем файл StiCrossTabTest.exe, он загружает отчёт "data.mrt", и словарь "Dictionary Designer.dct" (ссылается на "data.xml" и "schema.xsd").
На форме нажимаем "Run", ждём пока сформируются 77 страниц.
Теперь жмём "Close" в самом отчёте, появится кнопка "Run", нажимаем её ещё раз, - в этот раз получаем System.OutOfMemory:
---
----------------------------
[Customer Explanation]
----------------------------
[General Info]

Application: StiCrossTabTest
Framework: v4.0.30319
Version: Version: 2014.3.0 from 1 December 2014
MachineName: VS-LEON-PROGRAM
OSVersion: Microsoft Windows NT 6.1.7600.0
UserName: leon
----------------------------
[Exception Info]
Message: Exception of type 'System.OutOfMemoryException' was thrown.

Source: mscorlib

StackTrace:
at System.Object.MemberwiseClone()
at Stimulsoft.Base.Services.StiService.Clone()
at Stimulsoft.Report.Components.StiComponent.Clone(Boolean cloneProperties)
at Stimulsoft.Report.Components.StiSimpleText.Clone(Boolean cloneProperties)
at Stimulsoft.Report.Components.StiText.Clone(Boolean cloneProperties)
at Stimulsoft.Report.CrossTab.StiCrossSummary.Clone(Boolean cloneProperties)
at Stimulsoft.Report.Components.StiComponent.Clone()
at Stimulsoft.Report.CrossTab.Core.StiGrid.SetCell(Int32 cellX, Int32 cellY, Int32 cellWidth, Int32 cellHeight, Object text, Object value, StiCrossField field, Boolean isNumeric, Object hyperlink, Object toolTip, Object tag, Dictionary`2 drillDownParameters, Int32 level)
at Stimulsoft.Report.CrossTab.Core.StiGrid.SetCell(Int32 cellX, Int32 cellY, Int32 cellWidth, Int32 cellHeight, Object text, Object value, StiCrossField field, Boolean isNumeric, Object hyperlink, Object toolTip, Object tag, Dictionary`2 drillDownParameters)
at Stimulsoft.Report.CrossTab.Core.StiCross.SetCellValue(Int32 x, Int32 y, Object value, Int32 calcIndex, Int32 level, StiFieldType fieldType, Object hyperlinkValue, Object toolTipValue, Object tagValue, Dictionary`2 drillDownParameters)
at Stimulsoft.Report.CrossTab.Core.StiCross.CopySummary(StiSummary summary, Int32 left, Int32 top, Int32 colIndex, Int32 rowIndex, Boolean setValue, Boolean grandTotal, Object emptyValue)
at Stimulsoft.Report.CrossTab.Core.StiCross.CopySummaries(Int32 left, Int32 top, Object emptyValue)
at Stimulsoft.Report.CrossTab.Core.StiCross.Create(DataTable table, StiReport report, StiSummaryDirection direction, String emptyValue)
at Stimulsoft.Report.CrossTab.StiCrossTabHelper.BuildCross(StiCrossTab masterCrossTab, Boolean designTime)
at Stimulsoft.Report.CrossTab.StiCrossTabHelper.CreateCross(StiCrossTab masterCrossTab)
at Stimulsoft.Report.Engine.StiPageHelper.RenderPage(StiPage page)
at Stimulsoft.Report.Engine.StiRenderProviderV2.RenderReport(StiReport report, StiReport masterReport, StiRenderState state)
at Stimulsoft.Report.Engine.StiRenderProviderV2.Render(StiReport report, StiRenderState state)
at Stimulsoft.Report.Engine.StiReportV2Builder.RenderSingleReport(StiReport masterReport, StiRenderState renderState)
at Stimulsoft.Report.StiReport.RenderReport(StiRenderState renderState)
at Stimulsoft.Report.StiReport.Render(StiRenderState renderState, StiGuiMode guiMode)
at Stimulsoft.Report.StiReport.Render(StiRenderState renderState)
at Stimulsoft.Report.StiReport.Render(Boolean showProgress, Int32 fromPage, Int32 toPage)
at Stimulsoft.Report.StiReport.Render(Boolean showProgress)
at Stimulsoft.Report.Design.Controls.StiDesignerPreviewControl.btRefresh_Click(Object sender, EventArgs e)

----------------------------
[Assemblies]
mscorlib, Version = 4.0.0.0
Oracle.DataAccess, Version = 2.112.1.0
Stimulsoft.Report, Version = 2014.3.0.0
Stimulsoft.Report.Win, Version = 2014.3.0.0
System, Version = 4.0.0.0
System.Data, Version = 4.0.0.0
System.Drawing, Version = 4.0.0.0
System.Windows.Forms, Version = 4.0.0.0
---
Вложения
exception.png
exception.png (16.53 КБ) 5049 просмотров
StiCrossTabTest2.7z
(679.34 КБ) 105 скачиваний
HighAley
Сообщения: 1975
Зарегистрирован: 08 июн 2011, 07:36

Re: CrossTab System.OutOfMemory

Сообщение HighAley » 27 апр 2015, 12:40

Здравствуйте.

В вашем тестовом проекте Platform target установлен в x86.
Данные занимают в памяти слишком много места. Построенный отчёт ещё больше.
Соответственно, из-за ограничений .Net Framework, вы получаете Out of Memory exception.

Спасибо.
Леонид
Сообщения: 328
Зарегистрирован: 23 июл 2009, 05:53

Re: CrossTab System.OutOfMemory

Сообщение Леонид » 27 апр 2015, 13:19

Весь наш проект скомпилирован для x86 (6 филиалов в крупнейших городах РФ), в нашей программе работают сотни людей. На данный момент на x64 мы переходить не планируем, если вы об этом, хотя мне не ясна связь утечки памяти и платформы.

Более того, вы обратили внимание, что отчёт первый раз выполняется нормально, и только на второй раз выдаёт exception.
То есть, иными словами, если бы данных было больше, то отчёт вообще бы не выполнился, и это не проблема платформы, т.к. xml-файл всего 56 Mb.

У нас есть подобные отчёты, в которых нам приходится ограничивать для пользователей интервалы дат до одного года, т.к., если будет большое количество данных, то отчёт с CrossTab'ом так же выдаёт out of memory exception.

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

Посмотрел, в памяти приложение (тестовое, что в предыдущем посте) занимает 1.2 Gb, при втором запуске почти 1.7 Gb, на к примеру, памяти у меня 18 Gb.

Скомпилировал тот же самый тестовый проект под x64, - да, работает, но занимает в памяти уже 3 Gb и больше, а у пользователей как правило стоит 4 Gb.

Пробовал принудительно вызывать Garbage Collector после нажатия кнопки Close, - не помогает.

И мне не ясно, почему в первый раз отчёт рисуется корректно, а второй раз уже не хватает памяти?
HighAley
Сообщения: 1975
Зарегистрирован: 08 июн 2011, 07:36

Re: CrossTab System.OutOfMemory

Сообщение HighAley » 28 апр 2015, 08:19

Здравствуйте, Леонид.

По умолчанию на x86-процесс выделяется не более 2Гб адресного пространства.
Реально же для приложения доступно меньше.

При построении отчёта требуется значительно больше памяти чем размер xml-файла. Даже при загрузке вашей XML(56Мб) в DataSet c помощью метода ReadXml() процесс разрастается на 150Мб.
Для построения такого сложного компонента, как Cross-tab, для расчётов требуется намного больше памяти. Утечки памяти никакой нет. Вы не вызываете метод Dispose() для отчёта и начинаете строить отчёт ещё раз. Естественно, что использование памяти ещё возрастает.

Спасибо.
Леонид
Сообщения: 328
Зарегистрирован: 23 июл 2009, 05:53

Re: CrossTab System.OutOfMemory

Сообщение Леонид » 28 апр 2015, 12:31

Вы не вызываете метод Dispose()
. Так и есть. Почему я его должен вызывать, разве у вас есть неуправляемые объекты в коде отчёта?

Хорошо, стал вызывать метод, это разумеется не помогло, т.к. Garbage Collector сразу не подчистит эти объекты. Поэтому стал вызывать в том же простом примере вот так:

Код: Выделить всё

    private void stiPreview_Close(object sender, EventArgs e)
    {
      stiReport.Dispose();
      stiReport = null;

      stiPreview.Dispose();
      stiPreview = null;

      // без этих двух строк не будет актуально, т.к. пользователь сразу же запустит отчёт, выбрав другие даты, а память не будет освобождена
      GC.WaitForPendingFinalizers();
      GC.Collect();

      if (!button1.Visible)
        button1.Show();
    }
Это помогло, да, но есть проблема осталась. Если мы делаем выборку за два месяца, то Exception снова возникает. То есть, грубо говоря, это равносильно запуску тестового примера с xml-файлом не в 56Mb, а в два раза (или ещё) больше.

И что нам с этим делать в итоге, что сказать десяткам пользователей, которые пользуются отчётом?
Ответить