C #을 사용하여 필드 크기 (바이트) 가져 오기
클래스가 있고 필드를 검사하고 결국 각 필드가 차지하는 바이트 수를보고하고 싶습니다. 모든 필드가 Int32, 바이트 등의 유형이라고 가정합니다.
필드가 차지하는 바이트 수를 쉽게 알 수있는 방법은 무엇입니까?
다음과 같은 것이 필요합니다.
Int32 a;
// int a_size = a.GetSizeInBytes;
// a_size should be 4
기본적으로 할 수 없습니다. 패딩에 따라 다르며, 사용중인 CLR 버전과 프로세서 등을 기반으로 할 수 있습니다. 다른 개체에 대한 참조가 없다고 가정하면 개체의 전체 크기를 계산하는 것이 더 쉽습니다. 큰 배열을 만듭니다. 기준점으로 GC.GetTotalMemory 를 사용 하고 유형의 새 인스턴스에 대한 참조로 배열을 채운 다음 GetTotalMemory를 다시 호출합니다. 한 값을 다른 값에서 떼어 내고 인스턴스 수로 나눕니다. 새 JITted 코드가 숫자에 기여하지 않도록 미리 단일 인스턴스를 만들어야합니다. 예, 들리는 것처럼 엉망입니다.하지만 지금까지 좋은 효과를 내기 위해 사용했습니다.
어제 나는 이것에 대한 작은 도우미 클래스를 작성하는 것이 좋은 생각이라고 생각했습니다. 관심이 있으면 알려주세요.
편집 : 다른 두 가지 제안이 있으며 둘 다 해결하고 싶습니다.
첫째, sizeof 연산자 : 이것은 추상에서 유형이 차지하는 공간 의 양만 표시하며 패딩을 적용하지 않습니다. (구조 내 패딩은 포함되지만 다른 유형 내에서 해당 유형의 변수에 적용된 패딩은 포함되지 않습니다.)
다음으로 Marshal.SizeOf : 마샬링 후 관리되지 않는 크기 만 표시하며 메모리의 실제 크기는 표시하지 않습니다. 문서에 명시 적으로 다음과 같이 명시되어 있습니다.
반환되는 크기는 실제로 관리되지 않는 형식의 크기입니다. 개체의 관리되지 않는 크기와 관리되는 크기는 다를 수 있습니다. 문자 유형의 경우 크기는 해당 클래스에 적용된 CharSet 값의 영향을받습니다.
그리고 다시 패딩은 차이를 만들 수 있습니다.
패딩이 적절하다는 의미를 명확히하기 위해 다음 두 클래스를 고려하십시오.
class FourBytes { byte a, b, c, d; }
class FiveBytes { byte a, b, c, d, e; }
내 x86 상자에서 FourBytes 인스턴스는 12 바이트 (오버 헤드 포함)를 사용합니다. FiveBytes 인스턴스는 16 바이트를 사용합니다. 유일한 차이점은 "e"변수입니다. 4 바이트가 필요합니까? 글쎄요 .. 당연히 FiveBytes에서 단일 변수를 제거하여 크기를 12 바이트로 되돌릴 수 있지만 그렇다고 각 변수가 4 바이트를 차지 한다는 의미는 아닙니다 (모두 제거하는 것을 고려하십시오!). 단일 변수의 비용은 여기에서 많은 의미가있는 개념이 아닙니다.
질문자의 필요에 따라 Marshal.SizeOf는 원하는 것을 제공하거나 제공하지 않을 수 있습니다. (Jon Skeet이 답변을 게시 한 후 편집 됨).
using System;
using System.Runtime.InteropServices;
public class MyClass
{
public static void Main()
{
Int32 a = 10;
Console.WriteLine(Marshal.SizeOf(a));
Console.ReadLine();
}
}
jkersch가 말했듯이 sizeof는 사용할 수 있지만 불행히도 값 유형에만 사용할 수 있습니다. 클래스 크기가 필요한 경우 Marshal.SizeOf를 사용하면됩니다.
Jon Skeet은 sizeof도 Marshal.SizeOf도 완벽하지 않은 이유를 설명했습니다. 질문자는 자신의 문제가 어느 쪽이든 받아 들일 수 있는지 결정해야한다고 생각합니다.
그의 답변에있는 Jon Skeets 레시피에서 나는 그가 참조하는 도우미 클래스를 만들려고했습니다. 개선을위한 제안을 환영합니다.
public class MeasureSize<T>
{
private readonly Func<T> _generator;
private const int NumberOfInstances = 10000;
private readonly T[] _memArray;
public MeasureSize(Func<T> generator)
{
_generator = generator;
_memArray = new T[NumberOfInstances];
}
public long GetByteSize()
{
//Make one to make sure it is jitted
_generator();
long oldSize = GC.GetTotalMemory(false);
for(int i=0; i < NumberOfInstances; i++)
{
_memArray[i] = _generator();
}
long newSize = GC.GetTotalMemory(false);
return (newSize - oldSize) / NumberOfInstances;
}
}
용법:
T의 새 인스턴스를 생성하는 Func를 사용하여 만들어야합니다. 매번 동일한 인스턴스가 반환되지 않도록합니다. 예 : 이것은 괜찮을 것입니다 :
public long SizeOfSomeObject()
{
var measure = new MeasureSize<SomeObject>(() => new SomeObject());
return measure.GetByteSize();
}
이 기능을 IL 수준까지 줄여야했지만 마침내 매우 작은 라이브러리를 사용하여이 기능을 C #으로 가져 왔습니다.
bitbucket 에서받을 수 있습니다 (BSD 라이선스).
예제 코드 :
using Earlz.BareMetal;
...
Console.WriteLine(BareMetal.SizeOf<int>()); //returns 4 everywhere I've tested
Console.WriteLine(BareMetal.SizeOf<string>()); //returns 8 on 64-bit platforms and 4 on 32-bit
Console.WriteLine(BareMetal.SizeOf<Foo>()); //returns 16 in some places, 24 in others. Varies by platform and framework version
...
struct Foo
{
int a, b;
byte c;
object foo;
}
Basically, what I did was write a quick class-method wrapper around the sizeof
IL instruction. This instruction will get the raw amount of memory a reference to an object will use. For instance, if you had an array of T
, then the sizeof
instruction would tell you how many bytes apart each array element is.
This is extremely different from C#'s sizeof
operator. For one, C# only allows pure value types because it's not really possible to get the size of anything else in a static manner. In contrast, the sizeof
instruction works at a runtime level. So, however much memory a reference to a type would use during this particular instance would be returned.
You can see some more info and a bit more in-depth sample code at my blog
It can be done indirectly, without considering the alignment. The number of bytes that reference type instance is equal service fields size + type fields size. Service fields(in 32x takes 4 bytes each, 64x 8 bytes):
- Sysblockindex
- Pointer to methods table
- +Optional(only for arrays) array size
So, for class without any fileds, his instance takes 8 bytes on 32x machine. If it is class with one field, reference on the same class instance, so, this class takes(64x):
Sysblockindex + pMthdTable + reference on class = 8 + 8 + 8 = 24 bytes
If it is value type, it does not have any instance fields, therefore in takes only his fileds size. For example if we have struct with one int field, then on 32x machine it takes only 4 bytes memory.
if you have the type, use the sizeof operator. it will return the type`s size in byte. e.g.
Console.WriteLine(sizeof(int));
will output:
4
You can use method overloading as a trick to determine the field size:
public static int FieldSize(int Field) { return sizeof(int); }
public static int FieldSize(bool Field) { return sizeof(bool); }
public static int FieldSize(SomeStructType Field) { return sizeof(SomeStructType); }
Simplest way is: int size = *((int*)type.TypeHandle.Value + 1)
I know this is implementation detail but GC relies on it and it needs to be as close to start of the methodtable for efficiency plus taking into consideration how GC code complex is nobody will dare to change it in future. In fact it works for every minor/major versions of .net framework+.net core. (Currently unable to test for 1.0)
If you want more reliable way, emit a struct in a dynamic assembly with [StructLayout(LayoutKind.Auto)]
with exact same fields in same order, take its size with sizeof IL instruction. You may want to emit a static method within struct which simply returns this value. Then add 2*IntPtr.Size for object header. This should give you exact value.
But if your class derives from another class, you need to find each size of base class seperatly and add them + 2*Inptr.Size again for header. You can do this by getting fields with BindingFlags.DeclaredOnly
flag.
참고URL : https://stackoverflow.com/questions/207592/getting-the-size-of-a-field-in-bytes-with-c-sharp
'IT Share you' 카테고리의 다른 글
Mongoose : 단일 호출로 여러 쿼리 채우기 (0) | 2020.12.03 |
---|---|
Javascript .querySelector 찾기 (0) | 2020.12.03 |
JavaScript에서 문자열을 수학 표현식으로 평가 (0) | 2020.12.03 |
Eclipse에서 LogCat 실행이 중지되면 다시 시작해야 함 (0) | 2020.12.03 |
파일 찾기에서 정규식을 사용하는 방법 (0) | 2020.12.03 |