Является ли CancellationTokenSource неуправляемым ресурсом?
Всем привет. Есть вопрос касательно неуправляемых ресурсов. На сколько я понимаю GC не может самостоятельно их очистить, для этого существует интерфейс IDisposable. Следовательно CancellationToken который реализует данный интерфейс является неуправляемым ресурсом. Если я напишу такой код. Получу ли я out memory exception с течением времени ?
private void Update()
{
var token = new CancellationTokenSource();
}
Ну обычно CancellationToken берется из CancellationTokenSource.
Ну по идее в вашем случае, token может быть удален сразу после завершения метода Update, потому-что на него есть единственная ссылка которая существовала внутри видимости метода update
Pragma Games, Ну так вы не путайте структуру CancellationToken и CancellationTokenSource .
Да для CancellationTokenSource необходимо вызвать метод dispose, после того как он уже не нужен.
Например в конце задачи или через continuewith, если не вызовите, то это будет утечка памяти. Если он используется раз в 100 лет может и незаметная, но если часто, то рост будет активным.
twobomb, Да, вы правы, я изначально напутал. Я только начал использовать CancellationTokenSource. Мне стало любопытно и я написал такой код
private void Update()
{
var token = new CancellationTokenSource();
}
Но в memory profiler unity я не увидел утечку по памяти, GC все чистит, насколько я понимаю. И поэтому зная что после использования CancellationTokenSource необходимо вызвать метод dispose у меня вызвал интерес что и без dispose никаких утечек нет.
Pragma Games, Ну сейчас нет, потом будут. Потому-что у вас не типичное использование, которые не затрагивает ресурсы которые могут вызвать учетку.
Просто открываете код CancellationTokenSource
Ваш пример подпадает под безобиндный конструктор
public CancellationTokenSource()
{
m_state = NOT_CANCELED;
}
Но если вы бы использовали Timespan то всё было бы по другому, так как был бы вызван конструктор
public CancellationTokenSource(TimeSpan delay)
{
long totalMilliseconds = (long)delay.TotalMilliseconds;
if (totalMilliseconds < -1 || totalMilliseconds > Int32.MaxValue)
{
throw new ArgumentOutOfRangeException("delay");
}
InitializeWithTimer((int)totalMilliseconds);
}
В котором есть метод InitializeWithTimer, который создаёт таймер, а это уже страшная вещь за которой нужно следить.
Чтобы понять какие ресурсы могут вызывать учетку просто посмотри какие ресуры освобождаются в методе dispose
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (m_disposed)
return;
if (m_timer != null) m_timer.Dispose();
var linkingRegistrations = m_linkingRegistrations;
if (linkingRegistrations != null)
{
m_linkingRegistrations = null; // free for GC once we're done enumerating
for (int i = 0; i < linkingRegistrations.Length; i++)
{
linkingRegistrations[i].Dispose();
}
}
// registered callbacks are now either complete or will never run, due to guarantees made by ctr.Dispose()
// so we can now perform main disposal work without risk of linking callbacks trying to use this CTS.
m_registeredCallbacksLists = null; // free for GC.
if (m_kernelEvent != null)
{
m_kernelEvent.Close(); // the critical cleanup to release an OS handle
m_kernelEvent = null; // free for GC.
}
m_disposed = true;
}
}
Как видите это тот самый таймер, а также некоторые массивы и событие.
Соответственно если по каким причинам не было использования этих ресурсов в данном классе, то и освобождать ничего не нужно, ну откуда вы знаете в какие сценариях будут они использованы, а в каких нет? Нормальные люди в такие дебри не лезут, раз нужно вызывать Dispose , вызывайте его. Да в некоторых случаях этот вызов будет бесполезен, а в некоторых очень даже нужен.
Вы сделайте какую нибудь подписку на событие этого классе, и всё, будет например использован какой нибудь из тех массивов которые должны освобождаться, а вызова Dispose вы не делали, ну и пойдет утечка.
Всё зависит от сценария использования и внутренних реализаций таких классов, внутрь которых лезть не нужно. Просто вызывайте Dispose если ресурс больше не нужен, и не думайте.
IDisposable служит для реализации освобождения каких либо ресурсов. Сам по себе он к термину "неуправляемых ресурсов" отношения не имеет.
Создавать в Update его практически не имеет смысла, ты не сможешь им что либо отменить.
Я понимаю что создавать в Update его не имеет смысла. Мне интересно другое. Если класс реализует IDisposable, то разумно предположить, что он использует неуправляемые ресурсы прямо или косвенно ? Или это не так ?
Василий Банников, Зачем может потребоваться его реализовывать в классе или структуре если там нет неуправляемых ресурсов и GC и так сможет их очистить и без IDisposable ?
Pragma Games, Что тут объяснять, уже написал, что это просто удобное месте, если тебе надо освободить ресурсы. А что ты там будешь делать на самом деле зависит только от автора, может он там наоборот генерирует объекты.
GC вообще тут не причём, IDisposable не управляет жизнью объектов.
freeExec, Я задаю эти вопросы так как в документации microsoft, интерфейс IDisposable идет рядом с термином "неуправляемые ресурсы". Если в IDisposable автор генерирует объекты значит он не использует его по назначению. Если GC тут не причем, а IDisposable не управляет жизнью объектов, тогда почему мы не можешь обратиться к объекту у которого был вызван метод Dispose
"Dispose Используйте метод этого интерфейса для явного освобождения неуправляемых ресурсов в сочетании с сборщиком мусора. Потребитель объекта может вызвать этот метод, если объект больше не нужен."
Pragma Games, почему не можем, может, с объектом нечего не произошло. Просто он внутри себя пометил, что был вызван Dispose и дальнейшая работа может быть не корректна, поэтому шлёт тебя нафиг.
Если уж прям так чешется, то возьми и посмотри что там внутри, если анонимам из интернета ты не веришь.
freeExec, Я верю анонимам и тебе лично, иначе я бы не сидел на этом форму ) Так же я осознаю что ты знаешь гораздо больше меня. Просто я пытаюсь сопоставить информацию которой владею я, и ту которую преподносишь мне ты. Мои знания чисто теоретические, твои практические, что более весомо. Поэтому я и задаю возможно глупые вопросы по твоему мнению.
Я прочитал абзац
"Dispose Используйте метод этого интерфейса для явного освобождения неуправляемых ресурсов в сочетании с сборщиком мусора. Потребитель объекта может вызвать этот метод, если объект больше не нужен."
Соответственно у меня сложилось какое-то представление об этом. Абзац показывает видение "авторов" интерфейса о его предназначении. Потом я узнаю что IDisposable может реализовать любой в любом месте и еще для целей типо генерировать объекты. Тот же CancellationTokenSource наверняка реализует IDisposable исходя из принципов которые указаны в документации, иначе получается что документация не релевантна ? Вобщем придется идти и смотреть что там внутри )
freeExec, Меня напрягает что CancellationTokenSource реализует IDisposable, но если не делать dispoce никакой утечки по памяти нет, на сколько я могу судить. То есть не важно вызываешь dispoce или не вызываешь. Я говорю именно в этом контексте
private void Update()
{
var token = new CancellationTokenSource();
}
Pragma Games, освобождение неуправляемых ресурсов - первая и главная причина использовать IDisposable.
Но он может использоваться в принципе везде где есть семантика "освобождения" или "закрытия".
Например у логгера есть BeginScope который позволяет открыть скоуп логгера. В этом скоупе никаких неуправляемых ресурсов нет. Dispose используется только для того чтобы показать границы этого скоупа.
Логика подсказывает, что у CTS должно быть что-то похожее, но только чтобы отменить всё (пойду проверю исходники)
Pragma Games, ну короче у CTS из освобождаемых ресурсов есть:
1. Таймер
2. ManualResetEvent
3. Некий Registration
Так что неуправляемые ресурсы действительно есть, но они и так в принципе рано или поздно должны очиститься, тк на это есть финалайзер.
Но лучше всё-таки вызвать Dispose