C ++ / CX обнаруживает и решает циклы объектов? - PullRequest
11 голосов
/ 16 сентября 2011

Из моего понимания C ++ / CX не использует сборку мусора, вместо этого он использует метод подсчета ссылок.

Проблема с подсчетом ссылок заключается в том, что он не может избавиться от циклов. Циклы обычно решаются с использованием слабых ссылок, таких как weak_ptr в стандарте C ++.

Но я не могу найти способ в C ++ / CX явно указать слабую ссылку. Исходя из этого, я предполагаю, что это обрабатывается самим C ++ / CX. Мне интересно, как C ++ / CX решил бы это.

Например, посмотрите на следующий код:

ref class Foo
{
public:
    Bar^ bar;
};

ref class Bar
{
public:
    Foo^ foo;
};

ref class App
{
public:
    virtual void OnLaunched(LaunchActivatedEventArgs^ args)
    {
        Foo^ foo = ref new Foo();
        Bar^ bar = ref new Bar();
        foo.bar = bar;
        bar.foo = foo;
    }
};

Как C ++ / CX обнаруживает этот цикл?

Как C ++ / CX решает этот цикл?

Как C ++ / CX решает, какой из этих объектов должен быть «корневым объектом», а какой - «слабой ссылкой»?

Ответы [ 6 ]

12 голосов
/ 17 сентября 2011

Краткий ответ: нет, C ++ / CX не обнаруживает и не решает циклы объектов.

Длинный ответ: сам WinRT имеет стандартный механизм для слабых ссылок. На уровне ABI это определяется в терминах интерфейсов IWeakReference и IWeakReferenceSource, которые вы можете увидеть в "% ProgramFiles% \ Windows Kits \ 8.0 \ Include \ winrt \ WeakReference.idl".

В C ++ / CX все ваши классы будут автоматически реализовывать IWeakReferenceSource, и, следовательно, на все их экземпляры можно будет ссылаться слабо. Чтобы получить и сохранить слабую ссылку на объект, вы должны использовать вспомогательный класс Platform::WeakReference (определенный в vccorlib.h):

Foo^ foo = ref new Foo;
Platform::WeakReference weakRef(foo);

чтобы получить обратно объект, используйте Resolve<T>:

foo = weakRef.Resolve<Foo>();

Как обычно, вы получите nullptr, если объект уже был уничтожен.

Кроме этого, экземпляр WeakReference ведет себя более или менее как интеллектуальный указатель - он копируемый, подвижный, сопоставимый, назначаемый из nullptr, имеет неявное преобразование в неопределенный тип bool и т. Д.

Обратите внимание, что начиная с бета-версии VS11 IDE Intellisense будет блокироваться на WeakReference, если вы попытаетесь его использовать, подчеркнув его загогулами и т. Д. Несмотря на все это, компилятор может справиться с ними очень хорошо.

1 голос
/ 17 сентября 2011

Проверьте, включен ли \ winrt \ WeakReference.h в SDK.Он определяет IWeakReference, который можно использовать для этой цели.

0 голосов
/ 22 ноября 2016

В Mozilla XPCOM реализован подход Бэкона , и этот в некоторой степени может быть перенесен в WinRT при необходимости.Вообще, избегать трассировки сборщика мусора - это хорошо.У разработчиков все еще есть множество способов утечки памяти , поэтому лучше не впадать в заблуждение.Кроме того, с точки зрения контроля циклическое владение не имеет смысла.Это похоже на то, как Мюнхгаузен вырывает себя из болота своими собственными волосами и держит себя в воздухе.Должна быть причина существования каждого объекта, и подсчет ссылок является проявлением этой причины.Еще одним проявлением является право на изменение, что приводит к созданию надежных методов копирования при записи, сильно зависящих от доступности счетчика ссылок.В средах, имеющих только трассирующую сборку мусора, нужно либо выполнить глубокое копирование изменяемых структур данных, чтобы защитить их от нежелательных мутаций, либо использовать неизменные структуры данных с большими штрафами за небольшие глубокие изменения.Или конвертируйте изменяемые и неизменяемые структуры данных туда и обратно.Кроме того, было подсчитано, что трассировка сборки мусора работает нормально только при наличии 5-кратной необходимой оперативной памяти (глубоко скопированные реплики не учитываются).Для сравнения, консервативные распределители используют в 2 раза больше необходимой оперативной памяти (из-за фрагментации).Не обманывайте себя: копирование сборщика мусора только ускоряет распределение, но тратит в 2,5 раза больше оперативной памяти, чем консервативный сборщик мусора с подсчетом ссылок, для достижения сопоставимой производительности.

Посмотрите на Apple.Они внедрили TGC в Objective-C 2.0 в качестве дополнительной функции, но затем устарели, и тонны приложений для iPhone живут без этого довольно хорошо.Айфоны славятся отличным пользовательским интерфейсом и длительным зарядом аккумулятора.Windows 10 зависает как ад на моем ПК с 4 ГБ ОЗУ, в то время как Mac OS X 10.4.10 Хакинтош работал довольно гладко на 1 ГБ ОЗУ.Может быть, это как-то связано, тебе так не кажется?Возможно, где-то случайно произошла утечка памяти, но, в конце концов, это трудно заметить по сравнению с зависаниями и огромным потреблением ОЗУ.

Огромное потребление ОЗУ приводит к тому, что программы переключаются на диск, и если они переключаются на диск, а затем начинают отслеживать мусорсбор, замененные страницы возвращаются обратно в оперативную память, а перемещение замененных страниц обратно в оперативную память происходит довольно медленно.Кроме того, при этом страницы других приложений должны быть выгружены в файл подкачки.Как мы знаем, приложения для трассировки мусора используют в 2,5 раза больше оперативной памяти, поэтому у этих приложений в 2,5 раза больше шансов перейти на подкачку.Внезапно другое приложение также запустит сборку мусора и будет вынуждено вернуть страницы в оперативную память, вытесняя страницы других приложений.И это идет и идет как вечный двигатель наоборот.Обычный вечный двигатель бесконечно генерирует энергию из воздуха, а вечный двигатель наоборот бесконечно тратит энергию впустую.Отслеживание сбора мусора - это алгоритм, который никогда не заканчивается.Время от времени он запускается эвристически, и известно только, когда это будет сделано, если ему повезет.Может быть, в этот раз нам повезет что-то собрать, может быть, во второй раз, может быть, в третий раз.Вы покидаете компьютер на долгое время в надежде, что он, в конце концов, сделает свое дело и, наконец, позволит вам работать, но этот бизнес никогда не заканчивается.Внезапно два приложения запускают трассировку мусора одновременно и начинают конкурировать за незанятую оперативную память.При трассировке сборки мусора, вероятно, будет несколько последовательных обращений к одной и той же странице, поэтому одна страница может переходить в своп и обратно несколько раз.В офисных средах только компьютер босса, вероятно, имеет много оперативной памяти, другие компьютеры стоят как можно дешевле.Кроме того, антивирус принудительно развертывается на каждом офисном ПК, и сотрудники офиса не могут от него избавиться.Антивирус сохраняет оперативную память для подписей в памяти, делая ее еще более разреженной, а также проверяет каждый ввод-вывод, включая файлы подкачки, замораживающиеся до полного безумия.Вот где ад на Земле.

Я спросил адвокатов по отслеживанию мусора, могут ли они наблюдать зависания, как я, и оказывается, что они помещают много памяти в свои ПК (например, 16 Гб на ноутбуке !!!), используют ее в однопользовательском режиме,и сборка мусора для них работает нормально.Черт возьми, им придется работать со своими разработками на самых дешевых офисных ПК с принудительно развернутым антивирусом.

Поэтому я предлагаю вам не смотреть только на проблему сбора циклов.Научитесь любить подсчет ссылок, НАСЛАЖДАЙТЕСЬ ЭТОМ и заставляйте пользователей наслаждаться вашими тонкими программами.Сделайте большую часть подсчета ссылок.Надежное копирование при записи для вложенных структур.Пулы соединений с базой данных с обернутыми соединениями, где соединения возвращаются в пул немедленно, когда на их оболочку больше не ссылаютсяПрозрачность сети.RAII.

А если у вас действительно нет других вариантов, позаимствуйте у Mozilla XPCOM.Кстати, в ОС Windows Mozilla XPCOM сообщается, что ABI идентичен Microsoft COM, но не уверен.

0 голосов
/ 05 октября 2011

Как сказал Павел Минаев, WinRT имеет стандартный механизм для слабых ссылок: интерфейсы IWeakReferenceSource / IWeakReference, вспомогательный класс WRL::WeakRef и т. Д.

К сожалению, классы, определенные с помощью ref class, не реализуют IWeakReferenceSource, и, по крайней мере в этой версии Developer Preview, я не смог найти способ добавить этот интерфейс.

Возможный обходной путь - реализовать класс WinRT без использования расширений C ++ / CX в «родном» C ++. Структура WRL значительно упрощает эту задачу (она делает для WinRT то, что ATL делал для COM).

Существует один из примеров WinRT (пример «Разработка DLL-сервера»), который показывает, как реализовать объект WinRT без использования ref. По умолчанию классы, наследуемые от WRL::RuntimeClass<Interface>, автоматически реализуют IWeakReferenceSource и поэтому предоставляют слабые ссылки.

0 голосов
/ 17 сентября 2011

Это не объекты WinRT, это объекты вашего пользовательского типа. Поскольку вы объявили их как ссылочные типы .NET (ref class) с использованием синтаксиса C ++ / CLI, они собирают мусор, как и все ссылочные типы .NET, с помощью теста достижимости, а не подсчета ссылок.

Объекты Win32 всегда подсчитывались, так что, похоже, WinRT ничего не меняет там. Он просто предоставляет классы C ++ RAII для вас, под Win32 программисты написали свои собственные обертки, чтобы воспользоваться преимуществами RAII.

0 голосов
/ 16 сентября 2011

Это будет тот же старый способ COM-программирования, ручного мышления и добавления явных вызовов decf.

...