Я создаю игру воксельного типа, и мне интересно, как хранятся методы объектов.
public class Voxel
{
byte x, y, z;
public virtual void Build(){}
}
public class Flat : Voxel
{
public override void Build(){}
}
Если я создаю экземпляр этого 1 миллион раз с разными дочерними классами вокселей, замедляет ли это наличие большего количества методов? Должен ли я максимально ограничить класс и не использовать методы, или методы сохраняются в памяти один раз?
Не удалось найти хороший дубликат, может быть C#: Таблицы виртуальных методов? Экземпляр класса имеет указатель на свою виртуальную таблицу, в него не включена вся виртуальная таблица, поэтому количество виртуальных методов не имеет большого значения (количество невиртуальных методов, конечно, тоже не имеет значения). . Но для миллионов вокселей вы можете в любом случае захотеть избежать каких-либо «накладных расходов на объект» и использовать какое-то другое расположение.
Если я создаю экземпляр этого 1 миллион раз с разными дочерними классами вокселей, замедляет ли это наличие большего количества методов?
Нет, это не так. Методы не хранятся в экземпляре класса. Все методы (статические или нет) являются частью класса, а не экземпляра. Единственное отличие от методов экземпляра состоит в том, что они имеют неявный указатель «контекст»/this
в качестве первого аргумента. Все это обрабатывается самим C#. Хотя экземпляры классов в целом несут немало накладных расходов. Мы не можем дать точные цифры, поскольку это зависит от архитектуры (32/64 бит) и некоторых других факторов, таких как выравнивание. Кроме того, когда ваш класс имеет виртуальные/абстрактные методы, ему нужна v-таблица, чтобы определить, где он может найти конкретные реализации методов. Хотя v-таблица для класса также завершается только один раз для каждого конкретного типа. Экземпляр имеет указатель на эту таблицу. Невиртуальные методы разрешаются через тип переменной, а виртуальные методы проходят динамическую отправку с использованием v-таблицы.
Поэтому количество методов не имеет значения. Как я уже сказал, классы могут быть немного сложнее, когда дело касается общего использования памяти. Однако структуры намного проще, поскольку они не могут быть производными и не могут иметь виртуальных методов. По этой причине экземпляр структуры не содержит никакой информации о типе, а только чистые данные, независимо от того, сколько методов у него может быть.
Методы экземпляров на самом деле работают очень похоже на методы расширения C#. Почти весь код на C#, за очень немногими исключениями, является статическим. Большинство этих исключений, таких как дженерики, просто требуют начального этапа своевременной компиляции и с этого момента также являются статическими.
Для большинства воксельных движков довольно необычно хранить позиции x,y,z внутри экземпляра. Обычно вы хотите максимально ограничить данные. Позиция обычно является свойством, выведенным из местоположения в массиве/сетке, и может быть передана необходимым методам. Типы блоков Minecraft являются классами, но каждый из этих классов имеет только один экземпляр, представляющий тип блока. Таким образом, каждый блок использует один и тот же экземпляр для магии виртуальных методов. Поскольку структуры являются типами значений, вы можете обернуть блок структурой и заставить структуру «перетаскивать» позицию для удобства. Хотя это слишком углубляется в конкретные варианты дизайна. В итоге вы обычно не хотите представлять каждый воксел экземпляром класса по разным причинам.
Наличие большего количества методов не влияет напрямую на производительность вашего приложения. Код выделяется только один раз в виде исполняемых инструкций в той части оперативной памяти, которая называется «сегментом кода», и все экземпляры этого класса будут указывать на эти инструкции.
Что действительно влияет на производительность, так это алгоритм внутри методов. Плохо написанные алгоритмы, которые неэффективно решают проблему, могут замедлить работу вашего приложения, особенно если у вас есть миллионы экземпляров, неоднократно запускающих этот код.
С точки зрения потребления памяти на него могут повлиять данные внутри класса, количество экземпляров и вызовы методов. Это то, что сохраняется динамически во время выполнения программы.
Один класс со структурой данных, такой как список или матрица, если он содержит десятки или сотни значений, не будет занимать много памяти. Однако по мере того, как оно вырастет до тысяч, оно начнет потреблять больше памяти. То же самое справедливо и для миллионов экземпляров: чем больше данных внутри класса, тем больше потребление памяти.
Честно говоря, сегодня это не такая уж большая проблема, потому что у нас достаточно памяти, чтобы обрабатывать миллионы и миллионы экземпляров и переменных, но всегда полезно следить за этим и создавать лучшие решения, если это становится узким местом, например, дизайн. выкройка Легковес может пригодиться в этой ситуации.
Также посмотрите это видео, чтобы понять, как в ваших приложениях обрабатывается память.
с точки зрения единства, если бы у вас был 1 миллион, вы, скорее всего, были бы в ecs и работали бы с системами