Наткнулся тут на один метод в WCF-сервисе, который возвращает DataTable, а это Disposable тип. И что-то я призадумался.. А кто и как должен запускать Dispose у таких объектов? Делается ли это по какому-то волшебству автоматически? Или нужно в явном виде делать Dispose после возвращения (в finally?..)
Может там настройки какие-то или параметры вроде
AutoDispose нужны?
Подскажите, если кто сталкивался.
Вообще я подумываю убрать этот DataTable оттуда, ибо нефиг. Но это долгий процесс, сейчас нужно убедиться, что там ресурсы не текут.
Здравствуйте, Artem Korneev, Вы писали:
AK>Наткнулся тут на один метод в WCF-сервисе, который возвращает DataTable, а это Disposable тип.
Ниччего страшного.
http://stackoverflow.com/questions/18869079/datatable-dispose-will-make-it-remove-from-memory
DataSet and DataTable don't actually have any unmanaged resources, so Dispose() doesn't actually do much. The Dispose() methods in DataSet and DataTable exists ONLY because of side effect of inheritance — in other words, it doesn't actually do anything useful in the finalization.
It turns out that DataSets, DataViews, DataTables suppress finalization in their constructors this is why calling Dispose() on them explicitly does nothing.
Ну и почему оно нужно было, тот же ответ:
Without a doubt, Dispose should be called on any Finalizable objects.
DataTables are Finalizable.
Calling Dispose significantly speeds up the reclaiming of memory.
MarshalByValueComponent calls GC.SuppressFinalize(this) in its Dispose() — skipping this means having to wait for dozens if not hundreds of Gen0 collections before memory is reclaimed.
Смысл в чём: MarshalByValueComponent (базовый тип DataTable/DataSet) имеет финалайзер и реализует IDisposable. По умолчанию любой наследник этого типа не может быть пожран GC сразу, нужно вызвать финализатор => объект переживает сборку мусора и будет собран только при уборке следующего поколения. Для датасетов это явно не лучшее решение, надеюсь, не надо объяснять, почему?
В качестве workaround конструктор датасета вызывает Gc.SuppressFinalise(), как бы намекая рантайму, что финалайзер не нужен. Благодаря этой нехитрой магии DataSet/DataTable собираются сразу, не дожидаясь вызова финалайзера и не засоряют память своими очень важными килобайтами.
Немножко более подробный ответ,
http://stackoverflow.com/a/1603516
Здравствуйте, Sinix, Вы писали:
AK>>Наткнулся тут на один метод в WCF-сервисе, который возвращает DataTable, а это Disposable тип.
S>Ниччего страшного.
[...]
S>MarshalByValueComponent calls GC.SuppressFinalize(this) in its Dispose() — skipping this means having to wait for dozens if not hundreds of Gen0 collections before memory is reclaimed.
Ну.. то есть оно как бы и не обязательно, но желательно. Так?..
У меня WCF-сервис и сейчас нарисовалась проблема с освобождением памяти. Так что вот это вот освобождение тут как раз в тему. Но как? Я пока написал это в таком виде:
public DataTable Foo()
{
DataTable dataTable = null;
try
{
dataTable = GetFoo();
return dataTable;
}
finally
{
dataTable.Dispose();
}
}
Вроде ничего не падает, но я пока сам до конца не понимаю этого куска.. Dispose() тут отрабатывает, это понятно. Но что там происходит с возвращением объекта? Успевает ли WCF сериализовать и отдать его клиенту? Гарантированно ли это? Что бы тут такое покурить для просветления?
Плюс, смущает то, что код, я так понимаю, не поддающийся юнит-тестированию — в юниттесте я, наверное, получу объект, над которым только что произвели Dispose() и тест просто упадёт.
Я бегло порылся по интернету и нашёл какие-то упоминания атрибута AutoDispose, но просветления пока не пришло. На StackOverflow тоже какая-то чехарда — кто-то пишет, что нужно самому Dispose() вызывать, кто-то другой говорит, что WCF сам всё сделает, третьи советуют вообще не связываться с IDisposable-типами. Я и сам склоняюсь к последнему, но это на будущее. А пока нужно просто утечку ресурсов заткнуть.
Здравствуйте, Artem Korneev, Вы писали:
AK>Здравствуйте, Sinix, Вы писали:
AK>>>Наткнулся тут на один метод в WCF-сервисе, который возвращает DataTable, а это Disposable тип.
S>>Ниччего страшного.
AK>[...]
S>>MarshalByValueComponent calls GC.SuppressFinalize(this) in its Dispose() — skipping this means having to wait for dozens if not hundreds of Gen0 collections before memory is reclaimed.
AK>Ну.. то есть оно как бы и не обязательно, но желательно. Так?..
AK>У меня WCF-сервис и сейчас нарисовалась проблема с освобождением памяти. Так что вот это вот освобождение тут как раз в тему. Но как? Я пока написал это в таком виде:
AK>AK>public DataTable Foo()
AK>{
AK> DataTable dataTable = null;
AK> try
AK> {
AK> dataTable = GetFoo();
AK> return dataTable;
AK> }
AK> finally
AK> {
AK> dataTable.Dispose();
AK> }
AK>}
AK>
AK>Вроде ничего не падает, но я пока сам до конца не понимаю этого куска.. Dispose() тут отрабатывает, это понятно. Но что там происходит с возвращением объекта? Успевает ли WCF сериализовать и отдать его клиенту? Гарантированно ли это? Что бы тут такое покурить для просветления?
AK>Плюс, смущает то, что код, я так понимаю, не поддающийся юнит-тестированию — в юниттесте я, наверное, получу объект, над которым только что произвели Dispose() и тест просто упадёт.
AK>Я бегло порылся по интернету и нашёл какие-то упоминания атрибута AutoDispose, но просветления пока не пришло. На StackOverflow тоже какая-то чехарда — кто-то пишет, что нужно самому Dispose() вызывать, кто-то другой говорит, что WCF сам всё сделает, третьи советуют вообще не связываться с IDisposable-типами. Я и сам склоняюсь к последнему, но это на будущее. А пока нужно просто утечку ресурсов заткнуть.
По умолчанию WCF автоматически вызывает Dispose для входных параметров и возвращаемого результата метода по окончании обработки.
Этим поведением можно управлять, применяя
OperationBehaviorAttribute.AutoDisposeParameters.