Правильное освобождение ресурсов
От: Аноним  
Дата: 11.11.10 11:59
Оценка:
Здравствуйте! Интересует такой вопрос, есть допустим такой код:


            var res = (HttpWebResponse)req.GetResponse();
            var sr = new StreamReader(res.GetResponseStream());
            var result = sr.ReadToEnd().Trim();
            res.Close();
            sr.Close();

            return result;


Прочитал где то, вот если взять этот пример, что закрывать sr тут не обязательно, достаточно закрыть только res, а потом sr сам закроется, верно ли такое утверждение? И вообще что лучше использовать, метод Close, или блок using? Спасибо за ответы.
освобождение ресурсов using close
Re: Правильное освобождение ресурсов
От: SanyaVB  
Дата: 11.11.10 12:30
Оценка: -2
Здравствуйте, Аноним, Вы писали:

А> Здравствуйте! Интересует такой вопрос, есть допустим такой код:



А>
А>            var res = (HttpWebResponse)req.GetResponse();
А>            var sr = new StreamReader(res.GetResponseStream());
А>            var result = sr.ReadToEnd().Trim();
А>            res.Close();
А>            sr.Close();

А>            return result;
А>


А>Прочитал где то, вот если взять этот пример, что закрывать sr тут не обязательно, достаточно закрыть только res, а потом sr сам закроется, верно ли такое утверждение?

Да, верное утверждение
A>И вообще что лучше использовать, метод Close, или блок using? Спасибо за ответы.

using вызывает метод Dispose() при выходе из блока. В данном примере думаю нет разницы.
Re: Правильное освобождение ресурсов
От: Sinix  
Дата: 11.11.10 12:53
Оценка: +2
Здравствуйте, Аноним, Вы писали:


А> закрывать sr тут не обязательно, достаточно закрыть только res, а потом sr сам закроется, верно ли такое утверждение? .

Да. Проще — вот так:
using (new StreamReader((HttpWebResponse)req.GetResponse())
{
  var result = sr.ReadToEnd().Trim();
}

А>И вообще что лучше использовать, метод Close, или блок using?
using или try/finally.
Re: Правильное освобождение ресурсов
От: k.o. Россия  
Дата: 11.11.10 16:00
Оценка: -1
Здравствуйте, Аноним, Вы писали:

А> Здравствуйте! Интересует такой вопрос, есть допустим такой код:



А>
А>            var res = (HttpWebResponse)req.GetResponse();
А>            var sr = new StreamReader(res.GetResponseStream());
А>            var result = sr.ReadToEnd().Trim();
А>            res.Close();
А>            sr.Close();

А>            return result;
А>


А>Прочитал где то, вот если взять этот пример, что закрывать sr тут не обязательно, достаточно закрыть только res, а потом sr сам закроется, верно ли такое утверждение?


Нет, не верно. Несмотря на то, что StreamReader это просто обёртка над Stream, нет никаких гарантий, что единственное, что делает StreamReader.Close — это вызов Stream.Close. Как правило, для всех объектов типов реализующих IDisposable необходимо вызывать метод Dispose.

А>И вообще что лучше использовать, метод Close, или блок using? Спасибо за ответы.


А что значит лучше?
Re[2]: Правильное освобождение ресурсов
От: Аноним  
Дата: 11.11.10 16:43
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, Аноним, Вы писали:


А>> Здравствуйте! Интересует такой вопрос, есть допустим такой код:



А>>
А>>            var res = (HttpWebResponse)req.GetResponse();
А>>            var sr = new StreamReader(res.GetResponseStream());
А>>            var result = sr.ReadToEnd().Trim();
А>>            res.Close();
А>>            sr.Close();

А>>            return result;
А>>


А>>Прочитал где то, вот если взять этот пример, что закрывать sr тут не обязательно, достаточно закрыть только res, а потом sr сам закроется, верно ли такое утверждение?


KO>Нет, не верно. Несмотря на то, что StreamReader это просто обёртка над Stream, нет никаких гарантий, что единственное, что делает StreamReader.Close — это вызов Stream.Close. Как правило, для всех объектов типов реализующих IDisposable необходимо вызывать метод Dispose.


Я сам в этой теме не очень компетентен, поэтому и спросил, сам как я понял, извиняюсь за может неправильную формулировку, ну вот допустим такую систему:


var foo1 = new foo1(bar);
var foo2 = new foo2(foo1);
var foo3 = new foo3(foo2);

foo1.Close();



Вот в таком случае тут достаточно освободить ресурсы только foo1 и как следствие произойдет освобождение foo2 и foo3, т.к как идет как бы иерархия вызова, освобождение первого порождает освобождение второго и тд. Может это звучит глупо, по этой причине и был задан этот вопрос Т.к самому показалось это немного странно, найти ссылку уже пожалуй не смогу.

А>>И вообще что лучше использовать, метод Close, или блок using? Спасибо за ответы.


KO>А что значит лучше?


Здесь я имел ввиду, как дела обстоят на практике, т.е кто чем пользуется, и может быть причины этого.
Re[3]: Правильное освобождение ресурсов
От: telek1024  
Дата: 11.11.10 16:55
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>var foo1 = new foo1(bar);
А>var foo2 = new foo2(foo1);
А>var foo3 = new foo3(foo2);

А>foo1.Close();
А>



А>Вот в таком случае тут достаточно освободить ресурсы только foo1 и как следствие произойдет освобождение foo2 и foo3, т.к как идет как бы иерархия вызова, освобождение первого порождает освобождение второго и тд. Может это звучит глупо, по этой причине и был задан этот вопрос Т.к самому показалось это немного странно, найти ссылку уже пожалуй не смогу.


Почему произойдёт освобождение foo2 и foo3? Они ничего не знают про то, что ты освобождён foo1. А foo1 ничего не знает про foo2 и про foo3, чтобы его закрыть.

Нужно наоборот вызывать foo3.Close(), который закроет foo2, который закроет foo1.
Re[4]: Правильное освобождение ресурсов
От: Аноним  
Дата: 11.11.10 17:18
Оценка:
Здравствуйте, telek1024, Вы писали:

T>Здравствуйте, Аноним, Вы писали:


А>>
А>>var foo1 = new foo1(bar);
А>>var foo2 = new foo2(foo1);
А>>var foo3 = new foo3(foo2);

А>>foo1.Close();
А>>



А>>Вот в таком случае тут достаточно освободить ресурсы только foo1 и как следствие произойдет освобождение foo2 и foo3, т.к как идет как бы иерархия вызова, освобождение первого порождает освобождение второго и тд. Может это звучит глупо, по этой причине и был задан этот вопрос Т.к самому показалось это немного странно, найти ссылку уже пожалуй не смогу.


T>Почему произойдёт освобождение foo2 и foo3? Они ничего не знают про то, что ты освобождён foo1. А foo1 ничего не знает про foo2 и про foo3, чтобы его закрыть.


T>Нужно наоборот вызывать foo3.Close(), который закроет foo2, который закроет foo1.


Я сделал такой вывод из первых ответов, а вообще эта тема с освобождением ресурсов у меня в голове кипит Вот взять реализацию POST метода:


        public static string SetRequest(string url, string cookies, string parameters)
        {
            var req = (HttpWebRequest)WebRequest.Create(url);
            req.Headers.Add(HttpRequestHeader.Cookie, cookies);
            req.ContentType = "application/x-www-form-urlencoded";
            req.AllowAutoRedirect = false;
            req.Method = "POST";

            var data = Encoding.UTF8.GetBytes(parameters);
            req.ContentLength = data.Length;

            Stream st = req.GetRequestStream();
            st.Write(data, 0, data.Length);
            st.Close();

            var res = (HttpWebResponse)req.GetResponse();
            var sr = new StreamReader(res.GetResponseStream());
            var result = sr.ReadToEnd().Trim();
            res.Close();
            sr.Close();

            return result;
        }


Порыскав по гуглу, посмотрев другие как это делают, и задался этим вопросом, все закрывают Stream, а вот с StreamReader и HttpWebResponse нет, некоторые только HttpWebResponse, а у другие вообще доходит до абсурда И кто прав, а кто нет, уже запутался.


    //clean up
    response.Close();
    response.GetResponseStream().Close();
    response.GetResponseStream().Dispose();
    reader.Close();
    reader.Dispose();
    reader = null;
    response = null;
    request = null;


Вот такое встречал, и поэтому решил узнать как все таки делать правильно, а не городить нелепые конструкции. Если например не нужно вызывать sr.Close(); и достаточно только res.Close(); то и писать так, что бы не было лишнего кода.
Re[5]: Правильное освобождение ресурсов
От: telek1024  
Дата: 11.11.10 17:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, telek1024, Вы писали:


T>>Здравствуйте, Аноним, Вы писали:


А>>>
А>>>var foo1 = new foo1(bar);
А>>>var foo2 = new foo2(foo1);
А>>>var foo3 = new foo3(foo2);

А>>>foo1.Close();
А>>>



А>>>Вот в таком случае тут достаточно освободить ресурсы только foo1 и как следствие произойдет освобождение foo2 и foo3, т.к как идет как бы иерархия вызова, освобождение первого порождает освобождение второго и тд. Может это звучит глупо, по этой причине и был задан этот вопрос Т.к самому показалось это немного странно, найти ссылку уже пожалуй не смогу.


T>>Почему произойдёт освобождение foo2 и foo3? Они ничего не знают про то, что ты освобождён foo1. А foo1 ничего не знает про foo2 и про foo3, чтобы его закрыть.


T>>Нужно наоборот вызывать foo3.Close(), который закроет foo2, который закроет foo1.


А>Я сделал такой вывод из первых ответов, а вообще эта тема с освобождением ресурсов у меня в голове кипит Вот взять реализацию POST метода:



А>
А>        public static string SetRequest(string url, string cookies, string parameters)
А>        {
А>            var req = (HttpWebRequest)WebRequest.Create(url);
А>            req.Headers.Add(HttpRequestHeader.Cookie, cookies);
А>            req.ContentType = "application/x-www-form-urlencoded";
А>            req.AllowAutoRedirect = false;
А>            req.Method = "POST";

А>            var data = Encoding.UTF8.GetBytes(parameters);
А>            req.ContentLength = data.Length;

А>            Stream st = req.GetRequestStream();
А>            st.Write(data, 0, data.Length);
А>            st.Close();

А>            var res = (HttpWebResponse)req.GetResponse();
А>            var sr = new StreamReader(res.GetResponseStream());
А>            var result = sr.ReadToEnd().Trim();
А>            res.Close();
А>            sr.Close(); //нет исходного кода, но очень кажется, что он внутри вызовет res.Close()

А>            return result;
А>        }
А>


А>Порыскав по гуглу, посмотрев другие как это делают, и задался этим вопросом, все закрывают Stream, а вот с StreamReader и HttpWebResponse нет, некоторые только HttpWebResponse, а у другие вообще доходит до абсурда И кто прав, а кто нет, уже запутался.


Лучше всего читать исходный код. В Java существует правило, что обёртка над потоком должна закрыть этот поток. Поэтому я и сказал, что в предыдущем примере нужно закрыть foo3, а тот закроет всё остальное.

Расскажу общий принцип. Обязательно нужно закрывать только те ресурсы, закрытие которых не гарантируется. Например поток файла или сетевой поток. Они закроются только при сборке их объекта, но никто не гарантирует, что сборщик мусора их соберёт. Большинство потоков являют собой буферы в памяти. Вот такие закрывать не обязательно. Единственный ресурс, который они потребляют — это память. А память управляется автоматически.

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

Хотя тут очень много зависит от внутренней реализации. Ещё раз скажу, что нужно читать код. Криворуких программистов полно. Я встречал HttpStream'ы, которые нужно было сбросить (сделать flush) перед закрытием, чтобы они работали нормально, хотя по документации это было необязательно.
Re[6]: Правильное освобождение ресурсов
От: Аноним  
Дата: 11.11.10 18:14
Оценка:
Здравствуйте, telek1024, Вы писали:

T>Здравствуйте, Аноним, Вы писали:


А>>Здравствуйте, telek1024, Вы писали:


T>>>Здравствуйте, Аноним, Вы писали:


А>>>>
А>>>>var foo1 = new foo1(bar);
А>>>>var foo2 = new foo2(foo1);
А>>>>var foo3 = new foo3(foo2);

А>>>>foo1.Close();
А>>>>



А>>>>Вот в таком случае тут достаточно освободить ресурсы только foo1 и как следствие произойдет освобождение foo2 и foo3, т.к как идет как бы иерархия вызова, освобождение первого порождает освобождение второго и тд. Может это звучит глупо, по этой причине и был задан этот вопрос Т.к самому показалось это немного странно, найти ссылку уже пожалуй не смогу.


T>>>Почему произойдёт освобождение foo2 и foo3? Они ничего не знают про то, что ты освобождён foo1. А foo1 ничего не знает про foo2 и про foo3, чтобы его закрыть.


T>>>Нужно наоборот вызывать foo3.Close(), который закроет foo2, который закроет foo1.


А>>Я сделал такой вывод из первых ответов, а вообще эта тема с освобождением ресурсов у меня в голове кипит Вот взять реализацию POST метода:



А>>
А>>        public static string SetRequest(string url, string cookies, string parameters)
А>>        {
А>>            var req = (HttpWebRequest)WebRequest.Create(url);
А>>            req.Headers.Add(HttpRequestHeader.Cookie, cookies);
А>>            req.ContentType = "application/x-www-form-urlencoded";
А>>            req.AllowAutoRedirect = false;
А>>            req.Method = "POST";

А>>            var data = Encoding.UTF8.GetBytes(parameters);
А>>            req.ContentLength = data.Length;

А>>            Stream st = req.GetRequestStream();
А>>            st.Write(data, 0, data.Length);
А>>            st.Close();

А>>            var res = (HttpWebResponse)req.GetResponse();
А>>            var sr = new StreamReader(res.GetResponseStream());
А>>            var result = sr.ReadToEnd().Trim();
А>>            res.Close();
А>>            sr.Close(); //нет исходного кода, но очень кажется, что он внутри вызовет res.Close()

А>>            return result;
А>>        }
А>>


Наверное c var'ами неудобно читать код.


public static string SetRequest(string url, string cookies, string parameters)
{
    HttpWebRequest req = (HttpWebRequest) WebRequest.Create(url);
    req.Headers.Add(HttpRequestHeader.Cookie, cookies);
    req.ContentType = "application/x-www-form-urlencoded";
    req.AllowAutoRedirect = false;
    req.Method = "POST";

    byte[] data = Encoding.UTF8.GetBytes(parameters);
    req.ContentLength = data.Length;

    Stream st = req.GetRequestStream();
    st.Write(data, 0, data.Length);
    st.Close();

    HttpWebResponse res = (HttpWebResponse) req.GetResponse();
    StreamReader sr = new StreamReader(res.GetResponseStream());
    string result = sr.ReadToEnd().Trim();
    res.Close();
    sr.Close();

    return result;
}


А>>Порыскав по гуглу, посмотрев другие как это делают, и задался этим вопросом, все закрывают Stream, а вот с StreamReader и HttpWebResponse нет, некоторые только HttpWebResponse, а у другие вообще доходит до абсурда И кто прав, а кто нет, уже запутался.


T>Лучше всего читать исходный код. В Java существует правило, что обёртка над потоком должна закрыть этот поток. Поэтому я и сказал, что в предыдущем примере нужно закрыть foo3, а тот закроет всё остальное.


T>Расскажу общий принцип. Обязательно нужно закрывать только те ресурсы, закрытие которых не гарантируется. Например поток файла или сетевой поток. Они закроются только при сборке их объекта, но никто не гарантирует, что сборщик мусора их соберёт. Большинство потоков являют собой буферы в памяти. Вот такие закрывать не обязательно. Единственный ресурс, который они потребляют — это память. А память управляется автоматически.


T>Однако многие потоки могут откладывать обработку данных. Поэтому их нужно закрывать, чтобы сбросить внутренние буферы.


Ясно, я это так себе примерно и представлял, просто немного не привычно все это после с++, где памятью нужно управлять самому, поэтому остались привычки, делать это самому, а не ждать когда там сборщик решит собрать мусор, так что благодарю за ответы

T>Хотя тут очень много зависит от внутренней реализации. Ещё раз скажу, что нужно читать код. Криворуких программистов полно. Я встречал HttpStream'ы, которые нужно было сбросить (сделать flush) перед закрытием, чтобы они работали нормально, хотя по документации это было необязательно.


Согласен, подождем ответов других участников, может придем к какому-то единому мнению
Re: Правильное освобождение ресурсов
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.11.10 00:06
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

А>Прочитал где то, вот если взять этот пример, что закрывать sr тут не обязательно, достаточно закрыть только res, а потом sr сам закроется, верно ли такое утверждение?


Лучше все же закрыть. Полагаться на внутреннюю реализацию в общем случае опасно.

А> И вообще что лучше использовать, метод Close, или блок using?


Обязательно using, либо хотя бы try.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476 on Windows 7 6.1.7600.0>>
AVK Blog
Re: Правильное освобождение ресурсов
От: QrystaL Украина  
Дата: 12.11.10 06:48
Оценка:
Здравствуйте, Аноним, Вы писали:
А> Здравствуйте! Интересует такой вопрос, есть допустим такой код:

А>
А>            var res = (HttpWebResponse)req.GetResponse();
А>            var sr = new StreamReader(res.GetResponseStream());
А>            var result = sr.ReadToEnd().Trim();
А>            res.Close();
А>            sr.Close();

А>            return result;
А>


А>Прочитал где то, вот если взять этот пример, что закрывать sr тут не обязательно, достаточно закрыть только res, а потом sr сам закроется, верно ли такое утверждение?

Лучше такими вопросами не заморачиваться, а принять за правило — если IDisposable реализован — значит стоит им воспользоваться. Эта абстракция нужна в том числе чтобы не думать о деталях внутренней реализация стримов, ридеров и т.п.

A>И вообще что лучше использовать, метод Close, или блок using? Спасибо за ответы.

С практической и эстестической точки зрения — using.

using (var res = (HttpWebResponse)req.GetResponse())
{
    using (var sr = new StreamReader(res.GetResponseStream()))
    {
        var result = sr.ReadToEnd().Trim();
    }
}
Re[3]: Правильное освобождение ресурсов
От: k.o. Россия  
Дата: 12.11.10 08:04
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, k.o., Вы писали:


KO>>Здравствуйте, Аноним, Вы писали:


А>>>Прочитал где то, вот если взять этот пример, что закрывать sr тут не обязательно, достаточно закрыть только res, а потом sr сам закроется, верно ли такое утверждение?


А>Вот в таком случае тут достаточно освободить ресурсы только foo1 и как следствие произойдет освобождение foo2 и foo3, т.к как идет как бы иерархия вызова, освобождение первого порождает освобождение второго и тд. Может это звучит глупо, по этой причине и был задан этот вопрос Т.к самому показалось это немного странно, найти ссылку уже пожалуй не смогу.


Что такое foo1 — foo3 я не знаю, поэтому кто из них кого будет освобождать неизвестно. Что касается StreamReader, то для него гарантируется, что он закроет поток, которым владеет, т.е. то, что получилось в результате res.GetResponseStream(). При этом сам res всё ещё нужно закрыть, т.е. правильнее будет закрыть и res и sr.

А>>>И вообще что лучше использовать, метод Close, или блок using? Спасибо за ответы.


KO>>А что значит лучше?


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


Как правило, используют using, т.к. это наиболее простой способ освобождения ресурсов при возникновении исключений. Вот твой исхожный пример:
            var res = (HttpWebResponse)req.GetResponse();
            var sr = new StreamReader(res.GetResponseStream());
            var result = sr.ReadToEnd().Trim();
            res.Close();
            sr.Close();

            return result;

Если в выделенной строке возникнет исключение, ни res, ни sr не будут закрыты. Можно использовать try/finally:
HttpWebResponse res = null;
StreamReader sr = null;
string result = null;
try
{
            res = (HttpWebResponse)req.GetResponse();
            sr = new StreamReader(res.GetResponseStream());
            result = sr.ReadToEnd().Trim();
}
finally
{
    if (res != null)
            res.Close();
    if (sr != null)
            sr.Close();
}

return result;


Или using:
using (var res = (HttpWebResponse)req.GetResponse())
using (var sr = new StreamReader(res.GetResponseStream()))
{
            var result = sr.ReadToEnd().Trim();[/b]

            return result;
}
Re[4]: Правильное освобождение ресурсов
От: Аноним  
Дата: 12.11.10 08:34
Оценка:
Ну все теперь определился точно, если реализован интерфейс IDisposable, значит будем использовать его, т.к это все таки хороший тон. На счет using, наверное все таки действительно это удобнее чем делать конструкцию try/finaly, хотя тут наверное дело вкуса уже. Еще раз благодарю участников за ответы, они очень помогли развеять сомнения!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.