Почему этот трюк управления памятью работает?

Относится к этой документации Unity и перейдите в раздел

Большая куча с медленной, но редкой сборкой мусора

    var tmp = new System.Object[1024];

    // make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks
    for (int i = 0; i < 1024; i++)
        tmp[i] = new byte[1024];

    // release reference
    tmp = null;

Фокус в том, чтобы предварительно выделить некоторые фрагменты памяти при запуске программы.

Почему этот трюк работает?

Являются ли куски некогда "зарегистрированными" (или "привязанными" ) к приложению, когда они предварительно выделены, так что даже если tmp освобождается, когда Start() завершено, ОС все еще остается обрабатывать эти куски как "зарегистрированные" в приложении? Поскольку куски "зарегистрированы" в приложении, размер кучи приложения расширяется до определенного размера, и в следующий раз, когда он приобретает кусок памяти, ОС просто выберет его из кучи этого приложения.

Является ли мое объяснение правильным? Независимо от того, да или нет, кто-то может объяснить более подробно, спасибо.

Ответ 1

Это не совсем трюк. Это то, как части Unity3D обрабатывают память.

В Unity3D есть объекты, которые обрабатываются Mono и будут собираться мусором, и объекты, которые обрабатываются Unity, которые не будут собирать мусор. Строки, ints и т.д. Автоматически очищаются Mono, и нам не нужно беспокоиться об этом. Текстура (2D) и т.д. Нет, и мы должны вручную распоряжаться этими объектами.

Когда выполняется запрос на память, первое, что происходит, - это то, что диспетчер памяти сканирует текущую выделенную память из ОС для куска, достаточно большого для хранения запрашиваемых данных. Если совпадение найдено, эта память используется. Если совпадение не найдено, приложение будет запрашивать дополнительную память из ОС для хранения ваших данных. Когда эти данные больше не используются, это сбор мусора, но приложение по-прежнему сохраняет эту память. По сути, он устанавливает флаг в памяти, чтобы сказать, что он "полезен" или перераспределяется. Это уменьшает запросы на память, сделанные в ОС, никогда не возвращая ее.

Это означает две вещи:

1) Ваша память приложений будет продолжать расти и не вернет память в ОС. На мобильных устройствах это опасно, так как если вы используете слишком много памяти, ваше приложение будет прекращено.

2) На самом деле ваше приложение может быть выделено гораздо больше, чем требуется на самом деле. Это связано с фрагментированной памятью. У вас может быть 10 МБ доступной памяти в пуле приложений, но не те куски достаточно велики, чтобы хранить данные, необходимые для хранения. Поэтому возможно, что приложение будет запрашивать больше памяти из ОС, потому что нет доступной части непрерывной памяти.

Поскольку вы создаете большой объект, поэтому запрашивая память, когда вы устанавливаете этот объект в null и сигнализируете сборщику мусора, что память больше не нужна приложению, быстрее перераспределять память, которая хранится в другой а не запрашивать дополнительную память из ОС. Именно по этой причине в теории этот конкретный метод является быстрым и приведет к снижению производительности, поскольку сборщик мусора вызывается реже. Тем более, что это большое смежное выделение памяти.

Ответ 2

Почему этот трюк работает?

Этот трюк работает, потому что приложение не возвращает память в ОС, если диспетчер памяти ОС не работает и явно просит их сделать это, в результате чего они будут освобождаться как можно больше. Существует предположение, что, как только память будет выделена, она будет необходима снова. Если он уже выделен, нет причин возвращать его обратно в ОС, если это действительно не нужно использовать.