.NET 트랩 6: 열거치 지속으로 인한 많은 공간 소모로부터
5969 단어 .net
이번에 여러분과 공유한 내용은 하나의 매개 값 목록에 대한 서열화에 기인하여 아래에 간략화된 코드가 재현될 수 있습니다.명확하게 보기 위해서 나는 매거의 기초 유형을 현식으로 지정하였다.
// 。
public enum SomeEnum :int
{
First,
Second,
Third,
... ...
}
// 。
var list = new List<SomeEnum>();
for (int i = 0; i < 1000; ++i)
{
list.Add((SomeEnum)(i % 3));
}
var formatter = new BinaryFormatter();
var stream = File.OpenWrite("c:\\a.data");
formatter.Serialize(stream, list);
stream.Close()
생성될 a.data 파일은 대략 얼마나 될까요?
4K 결과를 얻은 학우, 내 생각에는 이렇게 추정한 것 같다. SomeEnum 매거진은 int로 각 값이 4바이트를 차지하고 1000개는 약 4K 정도이다. 게다가 다른 서열화된 정보도 4K가 좀 많을 것이다.처음에 나도 이렇게 생각했는데, 소프트웨어에서 이런 목록이 수십 메가의 메모리를 차지할 때 비로소 문제가 드러났다.나는 아직도 천진하다고 생각한다. 그렇게 간결한 유형은 상응하는 간결한 서열화 방식이 있어야 한다고 생각한다. 나는 심지어 천진해서 이것이 문제라는 것을 깨닫지 못했다.
나는 Reflector로 구체적인 지구화 과정을 추적한 후에야 비로소 원래 있었던 것을 발견하였다.NET 프레임워크 내부에서 열거 값을 기본 유형처럼 처리하지 않고 일반적인 값 대상으로 처리한다.더 심각한 것은 값 대상에 대한 처리도 인용 대상처럼 ObjectId와mapId를 저장해야 한다는 것이다.나는 '의외' 라는 단어를 썼다. 왜냐하면 나는 정말 값 대상 (Value Type) 은 데이터일 뿐이고, 두 개의reference가 같은 값 대상을 인용하는 상황이 존재하지 않는다고 생각했기 때문이다. (나는 이렇게 말하는 것이 좀 이상하다는 것을 알고 있지만, 네가 나의 뜻을 이해하길 바란다.) 지금까지도 나는 그렇게 생각한다.
다음은 formatter.Serialize (stream,list) 이 코드가 실행되는 과정에서 어느 순간의 창고 상태는 대량의 굴절이 당신의 기분에 영향을 주지 않도록 함수 이름 부분만 보존합니다.
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.BinaryObject.Write(...)
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.__BinaryWriter.WriteObject(...)
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(...)
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(...)
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArrayMember(...)
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArray(...)
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(...)
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(...)
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(...)
mscorlib.dll!System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(System.IO.Stream serializationStream, object graph)
창고 꼭대기에는.NET framework 바이너리 서열화 중 Binary Object.Write 방법은 다음과 같습니다.
public void Write(__BinaryWriter sout)
{
sout.WriteByte(1);
sout.WriteInt32(this.objectId);
sout.WriteInt32(this.mapId);
}
즉, 열거 값을 쓸 때마다 시스템은 1 + 4 + 4 = 9 바이트의 추가 데이터를 먼저 쓴다!이렇게 계산하면 시작 코드에서 생성된 파일은 대략 1K * (9 + 4) = 13K!
요 며칠 동안 나는 왜 값 대상에 대해서도objectId와mapId를 써야 합니까?프레임워크의 코드의 실제 출력을 보면 시스템은'값이 같은 여러 개의 값 대상에 대해 한 개의 데이터만 저장할 수 없다'고 할 수 없다. 그러면 왜 이런 추가 데이터를 써야 합니까?이것에 대해 나는 여전히 이해할 수 없으니, 만약 아는 사람이 있다면 아낌없이 가르침을 주십시오.
이 문제를 해결하기 위해 저는 유형 내부에서List
같은 이유로 다음과 같은 값 유형에 대해 직접 사용해야 한다.NET가 제공하는 서열화 메커니즘은 대상을 저장할 때마다 두 배 이상의 공간을 추가로 소모한다.그래, 인용 유형도 마찬가지지만 그 말--나는 단지 이 문제를 의식하지 못했을 뿐이지, 아니면 아직 프레임워크의 거친 실현을 받아들일 수 없다!
[Serializable]
public struct Point
{
private float x, y;
}
이러한 문제를 피하기 위해 가장 직접적인 방법은 이러한 구성원을 포함하는 유형에서ISerializable 인터페이스를 실현하고 기본 형식으로 전환된 데이터를 저장하는 것이다.클래스에 서열화된 구성원이 비교적 많으면 다른 구성원들도 수동으로 처리할 수 있습니다.만약 흥미가 있다면 나의 또 다른 박문인 깊이 파고들다.NET 서열화 메커니즘 - 사용하기 쉬운 서열화 방안을 실현하다을 참고하여 통일된 메커니즘을 실현할 수 있는지 없는지를 볼 수도 있다.
마지막으로 다시 한 번 호소합니다. 마이크로소프트가 왜 이렇게 값 유형의 서열화를 처리해야 하는지 누가 나에게 알려줄 수 있습니까?
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
AS를 통한 Module 개발1. ModuleLoader 사용 2. IModuleInfo 사용 ASModuleOne 모듈...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.