Почему мой класс занимает столько места в памяти? - PullRequest
7 голосов
/ 17 января 2012

У меня будет буквально десятки миллионов экземпляров некоторого класса MyClass, и я хочу минимизировать его объем памяти.Вопрос об измерении того, сколько места занимает объект в памяти, обсуждался в Узнайте размер объекта .net Я решил последовать предложению Джона Скита, и это мой код:

   // Edit: This line is "dangerous and foolish" :-) 
   // (However, commenting it does not change the result)
   // [StructLayout(LayoutKind.Sequential, Pack = 1)]
   public class MyClass       
   {
      public bool isit;
      public MyClass nextRight;
      public MyClass nextDown;
   }

   class Program
   {
      static void Main(string[] args)
      {
         var a1 = new MyClass(); //to prevent JIT code mangling the result (Skeet)
         var before = GC.GetTotalMemory(true);   
         MyClass[] arr = new MyClass[10000];
         for (int i = 0; i < 10000; i++)
            arr[i] = new MyClass(); 

         var after = GC.GetTotalMemory(true);

         var per = (after - before) / 10000.0;
         Console.WriteLine("Before: {0} After: {1} Per: {2}", before, after, per);
         Console.ReadLine();
      }
   }

Я запускаю программу в 64-битной Windows, выбираю «release», цель платформы: «any cpu» и выбираю «optimize code» (параметры имеют значение, только если я явно нацеливаюсь на x86). Результат, к сожалению, 48байт на экземпляр.

Мой расчет будет 8 байтов на ссылку, плюс 1 байт для bool плюс некоторые ~ 8 байтов служебных данных.Что здесь происходит?Является ли это заговором для поддержания высоких цен на оперативную память и / или для раздувания кода, производимого не Microsoft?Ну, ладно, наверное, мой настоящий вопрос: что я делаю не так или как я могу минимизировать размер MyClass?

Редактировать: Я прошу прощения за небрежность в моем вопросе, я отредактировал пару имен идентификаторов.Моя конкретная и непосредственная задача состояла в том, чтобы создать «2-dim связанный список» в качестве разреженной логической реализации матрицы, где я могу легко получить перечисление установленных значений в заданной строке / столбце.[Конечно, это означает, что я должен также хранить координаты x, y в классе, что делает мою идею еще менее осуществимой]

Ответы [ 3 ]

26 голосов
/ 17 января 2012

Подойдите к проблеме с другого конца.Вместо того, чтобы задавать себе вопрос: «Как я могу сделать эту структуру данных меньше и при этом выделить их десятки миллионов?»Задайте себе вопрос: «Как я могу представить эти данные, используя совершенно другую структуру данных, которая гораздо более компактна?»

Похоже, вы создаете двунаправленный список bools, который, как вы заметили, использует тридцатьв пятьдесят раз больше памяти, чем нужно.Есть ли какая-то причина, почему вы не просто используете BitArray для хранения своего списка bools?

ОБНОВЛЕНИЕ:

на самом деле я пыталсяреализовать разреженную булеву двумерную матрицу

Ну, почему ты так не сказал в первую очередь?

Когда я хочу создать разреженную булеву двумерную матрицу огромного размера, я создаю неизменное постоянное булево дерево quadree с запоминающейся фабрикой.Если массив разреженный или даже если он плотный, но в некотором роде самоподобный, вы можете получить огромных сжатий.Квадратные массивы 2 64 x 2 64 Булевы легко представимы, хотя, очевидно, в виде реального массива, это будет больше памяти, чем существует в мире.

Я думал о том, чтобы сделать серию статей в блогах по этой технике;Я, вероятно, сделаю это в конце марта.

Вкратце, идея состоит в том, чтобы создать абстрактный класс Quad, который имеет два подкласса: Single и Multi.«Одиночный» - это даблтон, похожий на синглтон, но с двумя экземплярами, которые называются Истинными и Ложными.Multi - это Quad с четырьмя подвалами, называемыми NorthEast, SouthEast, SouthWest и NorthWest.

Каждый квад имеет целое число "уровень";уровень сингла равен нулю, а мульти с уровня n необходим, чтобы все его дочерние элементы были четырехугольниками уровня n-1.

Фабрика Multi запоминается;когда вы просите его создать новый Multi с четырьмя дочерними элементами, он обращается к кешу, чтобы узнать, делал ли он это раньше.Если это так, он не создает новый;он раздает старый.Поскольку Quads являются неизменяемыми, вам не нужно беспокоиться о том, что кто-то заменит Quad после того, как он будет в кеше.

Теперь посмотрим, сколько слов памяти (слово составляет 4 или 8 байтов в зависимости от архитектуры)"all false" Multi уровня n потребляет.Уровень 1 "all false" multi использует четыре слова для ссылок на своих дочерних элементов, слово для подсчета уровня (если необходимо; вам не нужно сохранять уровень в multi, хотя это помогает для отладки) и пару словдля блока синхронизации и так далее.Давайте назовем это восемью словами.(Кроме того, память для квадрата False Single, который, как мы можем предположить, является константой двух или трех слов, и, следовательно, может игнорироваться.)

Уровень 2 "все ложные" мульти потребляет те же восемь слов, нокаждый из его четырех детей одного уровня 1 мульти .Следовательно, общее потребление мульти-уровня 2 «все ложно», скажем, 16 слов.

То же самое для уровня 3, 4, ... и так далее.Общее потребление памяти для мульти уровня 64, которое логически представляет собой квадратный массив логических выражений размером 2 64 x 2 64 , составляет всего 64 x 16 слов памяти!

Имеет смысл?Надеюсь, этого наброска хватит, чтобы начать.Если нет, см. Мой блог в конце марта.

4 голосов
/ 17 января 2012

8 (ссылка на объект) + 8 (ссылка на объект) + 1 (bool) + 16 (заголовок) + 8 (ссылка в самом массиве) = 41

Даже если он внутренне выровнен, все будут выровненыв кучу.Итак, мы ищем не менее 48 байт.

Я не могу понять, почему вы хотите получить связанный список bools.Их список занял бы в 48 раз меньше места, и это еще до того, как вы перейдете к оптимизации хранения bool на бит, которая сделает его в 384 раза меньше.И легче манипулировать.

1 голос
/ 17 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...