Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Узнать размер Managed Класса (MC++,C#,...)

842
04 марта 2009 года
sigmov
301 / / 16.09.2008
Rus: Как получить размер managed, C#, MC++ класса?
Eng: How can getting the size of a managed, C#, MC++ class?

Сразу оговорюсь - это не вопрос как сделать, это код на ваш суд.

Просто нигде не встретил ответа на данный вопрос(а многих он интересовал) поэтому решил собрать свой велосипед!!!

Многие говорили, что размер класса 4 и я им искренне верю(ибо класс - это ссылта и в х32 ее размер действительно 4), но меня интересовал размер класса, как если бы он был структурой(т.е. размер памяти занимаемой внутренними полями) .

Код:
public ref class SizeOf
        {
            //Тип char в Unicode, связано с тем, что char в С# - 2байта, а в С++ - 1байт
            static Type^ CharType = __wchar_t::typeid;
        public:
            //Подгрузка словаря, чтоб последующие запросы размера данного типа были на порядок быстрее
            //За идею спасибо HARDCASE -> http://forum.codenet.ru/showthread.php?t=53595
            static Dictionary<Type^,int>^ DictTypeSize = gcnew Dictionary<Type^,int>();
            //Вычисление размера переменной
            generic<typename T>
            static int sizeOf(T obj)
            {
                Type^ Ty = obj->GetType();
                //Если объект является классом или структурой с автовыравниваем,
                //Узнать его размер sizeof() мы не можем
                if(Ty->StructLayoutAttribute->Value == LayoutKind::Auto)
                {
                    int j;
                    if(DictTypeSize->TryGetValue(Ty,j)) //Пробуем извлечь из словаря
                        return j;
                    else
                    {   //Рассчитываем размеры внутренних полей
                        array<FieldInfo^>^ Fields = Ty->GetFields(BindingFlags::Instance | BindingFlags::Public | BindingFlags::NonPublic);
                        array<int>^ Arr = gcnew array<int>(Fields->Length);
                        j=-1;
                        for each(FieldInfo^ inf in Fields)
                        {
                            Type^ fieldTy = inf->FieldType;
                            if(fieldTy -> IsClass)
                                Arr[++j]=4; //Если тип поля - класс, то это ссылка 4байта                          
                            else
                                if(fieldTy == CharType) Arr[++j] = 2;   //Если тип - char, то 2 байта
                                else Arr[++j] = sizeOf(fieldTy);        //Вычисляем размер структуры, зная ее тип
                        }
                        j=0;
                        for each(int ej in Arr)
                            j+=ej;
                        if(j%4!=0 && j>2) j+=4-j%4; //Учитываем свойство коробочки(если размер >2, то он кратен 4м)
                        DictTypeSize->Add(Ty,j);    //Записываем в словарь
                        return j;                  
                    }
                }
                else
                {
                    return sizeof(obj);
                }
            }
            //Вычисление размера типа данных
            static int sizeOf(Type^ Ty)
            {
                if(Ty->StructLayoutAttribute->Value == LayoutKind::Auto)
                {
                    int j;
                    if(DictTypeSize->TryGetValue(Ty,j))
                        return j;
                    else
                    {
                        array<FieldInfo^>^ Fields = Ty->GetFields(BindingFlags::Instance | BindingFlags::Public | BindingFlags::NonPublic);
                        array<int>^ Arr = gcnew array<int>(Fields->Length);
                        j=-1;
                        for each(FieldInfo^ inf in Fields)
                        {
                            Type^ fieldTy = inf->FieldType;
                            if(fieldTy -> IsClass)
                                Arr[++j]=4;                        
                            else
                            {
                                if(fieldTy == CharType) Arr[++j] = 2;
                                else Arr[++j] = sizeOf(fieldTy);
                            }
                        }
                        j=0;
                        for each(int ej in Arr)
                            j+=ej;
                        if(j%4!=0 && j>2) j+=4-j%4;
                        DictTypeSize->Add(Ty,j);
                        return j;                  
                    }
                }
                else return Marshal::SizeOf(Ty);
            }
        };


Забыл про ограничение - выравние:
Struct: Auto || Sequential (По умолчанию Sequential)
Class: Auto || Sequential (По умолчанию Auto)
341
05 марта 2009 года
Der Meister
874 / / 21.12.2007
А тестируете вы код как?
5
05 марта 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Der Meister
А тестируете вы код как?


Что-то не то в этом коде... Отражение конечно дело, да не всегда будет работать, я бы поискал в сторону запроса размера объекта у самой CLR - ей уж точно виднее.

341
05 марта 2009 года
Der Meister
874 / / 21.12.2007
Кажется, сама CLR ответа на этот вопрос не даст (разве что как разность значений, возвращаемых GC.GetTotalMemory()). Да и смысл-то какой во всём этом?
Кроме того, к классу прилагается ~8 байт в заголовке.
842
05 марта 2009 года
sigmov
301 / / 16.09.2008
Цитата:
А тестируете вы код как?


Запихиваю функцию в сборку и работаю из С#

Сравниваю с результатами:
unsafe C# есть функция sizeof(struct)
кроме того в С# есть Marshal.SizeOf(object obj)[LayoutKind::Sequential]

Цитата:
Что-то не то в этом коде... Отражение конечно дело, да не всегда будет работать, я бы поискал в сторону запроса размера объекта у самой CLR - ей уж точно виднее.



Полностью согласен - она же знает скоко памяти выделить под объект, но нигде освещения данного вопроса не нашел.....

842
05 марта 2009 года
sigmov
301 / / 16.09.2008
Цитата: Der Meister
Да и смысл-то какой во всём этом?
Кроме того, к классу прилагается ~8 байт в заголовке.


~4 байта - там записан HashCode - Идентификатор типа

А нужно это для:

Код:
static Object^ CloneEasy(Object^ obj)
            {
                if (dynamic_cast<ValueType^>(obj)==nullptr)
                {
                    int _size = SizeOf::sizeOf(obj);
                    Object^ copy;
                    if(_size>8) copy = gcnew array<int,1>(_size/4-2);
                    else if(_size==4) copy = gcnew Int32();
                    else if(_size==2) copy = gcnew __wchar_t();
                    else copy = gcnew Byte();
                    memcpy(Native::UnBox(&copy),Native::UnBox(&obj),_size+4);
                    return copy;
                }
                return obj;
            }

Клонирование 1000000 Объектов через
MemberwiseClone - 6,94 сек
MyClone - 1,12 сек
5
05 марта 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: sigmov
~4 байта - там записан HashCode - Идентификатор типа

А нужно это для:
Код:
static Object^ CloneEasy(Object^ obj)
            {
                if (dynamic_cast<ValueType^>(obj)==nullptr)
                {
                    int _size = SizeOf::sizeOf(obj);
                    Object^ copy;
                    if(_size>8) copy = gcnew array<int,1>(_size/4-2);
                    else if(_size==4) copy = gcnew Int32();
                    else if(_size==2) copy = gcnew __wchar_t();
                    else copy = gcnew Byte();
                    memcpy(Native::UnBox(&copy),Native::UnBox(&obj),_size+4);
                    return copy;
                }
                return obj;
            }
Клонирование 1000000 Объектов через
MemberwiseClone - 6,94 сек
MyClone - 1,12 сек

Ну, клонирование такого количества объектов обычно нафиг не нужно, а вот по ссылке пройти очень советую.

341
06 марта 2009 года
Der Meister
874 / / 21.12.2007
Цитата: sigmov
~4 байта - там записан HashCode - Идентификатор типа

Мне профайлер говорит, что 8. Правда, я подразумевал, что речь идёт о памяти, занимаемой экземпляром управляемого типа, а вы толкуете о размере той части данных управляемого объекта, которая получается в результате маршалинга в неуправляемый указатель. Это разные числа.
Идентификатор типа и хэш - тоже две большие разницы. Кроме того, хэш обычно не хранится, а вычисляется. И нужен он для ассоциативных коллекций, если вы об Object::GetHashCode().

Цитата: sigmov
Клонирование 1000000 Объектов через
MemberwiseClone - 6,94 сек
MyClone - 1,12 сек

Не думаю, что клонирование может стать узким местом в системе...

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог