Третий день гоняюсь за багом, связанным толи с утечкой ресурсов, толи памяти. Попутно наткнулся на одно место в клиентской части приложения, которое создаёт объект типа Stream и не освобождает его через Dispose:
using (new OperationContextScope((IClientChannel)service))
{
Stream tempStream = service.GetChunkedImageStream(imageUID, compress, quality);
{
WriteStreamToFile(file, tempStream);
}
}
tempStream надо бы тоже обернуть в using. Но что меня смутило — почему встроенный статический анализ ничего не сказал про это? В настройках проекта стоит анализ с набором правил "Microsoft Managed Recommended Rules" и никаких ворнингов на этой строке оно не показывает.
Умеет ли вообще встроенный анализатор ловить такое? Вроде не сложная вещь.
С уважением, Artem Korneev.
Re: using & disposable - как поймать статическим анализом?
Здравствуйте, Artem Korneev, Вы писали:
AK>Третий день гоняюсь за багом, связанным толи с утечкой ресурсов, толи памяти.
Если используется HttpRuntime.Cache или MemoryCache, то не лечится. Они всю память жрут. А про наследника Stream я бы в последнюю очередь подумал — Любой класс может оставлять мусор в памяти на долго долго.
Re: using & disposable - как поймать статическим анализом?
Здравствуйте, Artem Korneev, Вы писали:
AK>Умеет ли вообще встроенный анализатор ловить такое? Вроде не сложная вещь.
Например анализатор не знает что происходит внутри WriteStreamToFile, который может быть вообще во внешней библиотеке. В частности WriteStreamToFile внутри может (технически) вызывать tempStream.Dispose().
В C++ по-умолчанию реализован именно тот вариант о котором ты говоришь — автоматический scope'инг, причём без необходимости писать явный using, а если же нужно убежать из scope — то используется явный move.
Re: using & disposable - как поймать статическим анализом?
Здравствуйте, VladCore, Вы писали:
AK>>Третий день гоняюсь за багом, связанным толи с утечкой ресурсов, толи памяти. VC>Если используется HttpRuntime.Cache или MemoryCache, то не лечится. Они всю память жрут. А про наследника Stream я бы в последнюю очередь подумал — Любой класс может оставлять мусор в памяти на долго долго.
Ни HttpRuntime.Cache, ни MemoryCache там не использовался. Помимо Stream, я нашёл там кучу других претендентов — неосвобождённые SqlCommand, DataTable и прочее. В чём именно была проблема — так и не ясно, но после обёртывания этих Displosable-объектов в using и полного переписывания одного медленного и частоиспользуемого метода, проблема перестала воспроизводиться.
Но мой вопрос был больше о том, почему статический анализ не тыкал нас носом в неосвобождённый Disposable.
С уважением, Artem Korneev.
Re[2]: using & disposable - как поймать статическим анализом?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
AK>>Умеет ли вообще встроенный анализатор ловить такое? Вроде не сложная вещь. EP>Например анализатор не знает что происходит внутри WriteStreamToFile, который может быть вообще во внешней библиотеке. В частности WriteStreamToFile внутри может (технически) вызывать tempStream.Dispose().
WriteStreamToFile в том случае это локальный метод того же класса, и никаких .Dispose() там не вызывается.
С уважением, Artem Korneev.
Re[3]: using & disposable - как поймать статическим анализом?
Здравствуйте, Artem Korneev, Вы писали:
AK>>>Умеет ли вообще встроенный анализатор ловить такое? Вроде не сложная вещь. EP>>Например анализатор не знает что происходит внутри WriteStreamToFile, который может быть вообще во внешней библиотеке. В частности WriteStreamToFile внутри может (технически) вызывать tempStream.Dispose(). AK>WriteStreamToFile в том случае это локальный метод того же класса, и никаких .Dispose() там не вызывается.
Но анализатору нужно анализировать в том числе и этот метод, то есть поинт в том что локального анализа кода из первого сообщения недостаточно.
Это серьёзный барьер для анализаторов. Хотя, действительно, вполне преодолимый в некоторых частных случаях.
Re: using & disposable - как поймать статическим анализом?
В общем случае — не нужно: service вполне может владеть этим стримом, и сам диспозить его. Собственно потому что "Get...()" — не тоже самое, что Create....().
В случае Create() — да, нужно обязательно диспозить, а в случай Get намного сложнее, например: GetInternalBuffer() — попробуй сказать, надо диспозить или нет.
Всё сказанное выше — личное мнение, если не указано обратное.