Запрос используемой памяти приводит к сбою приложения? - PullRequest
0 голосов
/ 03 апреля 2012

На момент этого приложение занимало около 150 МБ памяти. Посмотрите на это:

Сообщение об исключении:

Исключение типа 'System.OutOfMemoryException' выдано.

трассировка стека: в System.Diagnostics.NtProcessInfoHelper.GetProcessInfos () в System.Diagnostics.ProcessManager.GetProcessInfos (String machineName) в System.Diagnostics.Process.EnsureState (состояние штата) в System.Diagnostics.Process.get_WorkingSet64 () в StreamSink.frmMain.get_MemoryUsed () в C: \ Projects \ VideoPhill \ PlayerRAC \ StreamSink \ StreamSink \ StreamSink \ frmMain.cs: строка 819 в StreamSink.frmMain.CalculateStatistics () в C: \ Projects \ VideoPhill \ PlayerRAC \ StreamSink \ StreamSink \ StreamSink \ frmMain.cs: строка 803 в StreamSink.frmMain._timerUI_Tick (Отправитель объекта, EventArgs e) в C: \ Projects \ VideoPhill \ PlayerRAC \ StreamSink \ StreamSink \ StreamSink \ frmMain.cs: строка 736 в System.Windows.Forms.Timer.OnTick (EventArgs e) в System.Windows.Forms.Timer.TimerNativeWindow.WndProc (Сообщение & m)

Ну, что здесь не так?

РЕДАКТИРОВАТЬ (подробнее):

Этот провал:

    private long MemoryUsed
    {
        get
        {
            return Process.GetCurrentProcess().WorkingSet64 / 1024 / 1024;
        }
    }

И вызывается из:

    private void CalculateStatistics()
    {
        if (InvokeRequired)
        {
            this.BeginInvoke(new MethodInvoker(CalculateStatistics));
        }
        else
        {
            barStaticItem1.Caption = "Mem: " + MemoryUsed.ToString() + " MB";
        }
    }

, который вызывается из события timer, а timer имеет тип: System.Windows.Forms.Timer.

* Ошибка не может быть воспроизведена сама по себе. *

Ответы [ 4 ]

1 голос
/ 15 апреля 2012

Я выхожу здесь на конечность и замечу, что в сделанных предположениях есть что-то подозрительное. Прежде всего, зачем вы пишете такой код? На самом деле обычно для приложения не хватает памяти, а это , почему вы хотите отобразить использование памяти в вашем пользовательском интерфейсе? Во-вторых, как вы уверены, что приложение на самом деле использует только 150 МБ, если это происходит в производственной среде, но не на вашем компьютере разработчика?

Я утверждаю, что исключение реально, а предположения неверны. Процесс фактически исчерпал память. То, что это произошло внутри кода, который был разработан для предупреждения пользователя о нехватке памяти, очень иронично. Но, конечно, это не невозможно, нативной функции ОС, которая предоставляет информацию, нужен довольно большой буфер, когда на машине запущено много процессов. Вместо этого вы должны были использовать свойство Environment.WorkingSet.

Также примечательно, что получить 150 МБ из WorkingSet и получить OOM вполне возможно. Это неправильная статистика памяти. WorkingSet описывает, сколько оперативной памяти вы используете. Но OOM срабатывает, когда у вас заканчивается виртуальная память . Две очень разные меры. WorkingSet низок, когда страницы виртуальной памяти выгружаются в файл подкачки. Что, скорее всего, произойдет, когда запущено множество процессов, конкурирующих за оперативную память.

Нет удобного свойства для измерения размера виртуальной машины. Главным образом, потому что это в значительной степени бесполезно, размер отверстий на карте памяти является тем, что важно. Вы получаете OOM, когда нет достаточно большого отверстия, чтобы соответствовать распределению. Если вы хотите отобразить полезную статистику, тогда GC.GetTotalMemory () несколько полезен. Только несколько, это не учитывает неуправляемую память в использовании. Решите все свои проблемы, указав в своих требованиях 64-разрядную операционную систему.

1 голос
/ 12 апреля 2012

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

Если вы не можетеПодумайте о любой причине, почему приложение должно использовать так много памяти, есть вероятность, что где-то может быть утечка памяти.Возможно, вы захотите захватить профилировщик памяти, например ANTS Memory Profiler , чтобы проверить, так ли это, и если да, то где он лежит.

0 голосов
/ 14 апреля 2012

Я думаю, что причиной сбоя было то, что код неоднократно выполнялся в фоновых потоках, и при рекурсивном вызове не было никаких условий выхода this.BeginInvoke(new MethodInvoker(CalculateStatistics));

Переход к следующему коду поможет решить проблему.

private void CalculateStatistics()
    {

        Action showMemoryUsage = () =>
                                     {
                                         barStaticItem1.Caption = "Mem: " + MemoryUsed.ToString() + " MB";
                                     };
        if (InvokeRequired)
        {
            this.BeginInvoke(new MethodInvoker(showMemoryUsage));
        }
        else
        {
            showMemoryUsage();
        }
    }
0 голосов
/ 11 апреля 2012

Ваш код действительно не отображается, если BeginInvoke что-то здесь делает (поскольку мы не знаем, когда InvokeRequired имеет значение true).

Так что, очевидно, этот код может давать сбой, так как весь другой код выглядит нормально:

Process.GetCurrentProcess().WorkingSet64 / 1024 / 1024;

Предлагаю вам сделать небольшое приложение, которое стресс-тестирует Process.GetCurrentProcess (). WorkingSet. Но, по правде говоря, я сомневаюсь, что это поможет (если только у вашей производственной машины нет проблем с оборудованием).

Я вижу, вы используете barStaticItem1 - должен быть элемент управления, не так ли? Что ж, если вы запускаете разные потоки, и этот элемент управления не является потокобезопасным или не должен использоваться из другого потока (отличается от потока, создавшего этот элемент управления), это может быть источником вашей проблемы: 1. встречается редко ; 2. Вы не можете сделать это, когда хотите.

...