우리의 응용 프로그램에는 무엇보다도 청크 분할 된 바이트 목록 (현재는 List<byte[]>
으로 표시됨)이 들어있는 데이터 구조가 있습니다. 바이트 배열을 대형 객체 힙에 넣을 수있게되면 시간이 지남에 따라 메모리 조각화가 발생하기 때문에 바이트를 채 웁니다.메모리 사용량이 Protobuf-net을 사용하여 청크 바이트 배열을 직렬화합니다.
또한 생성 된 직렬화 DLL을 사용하여 Protobuf-net을 사용하여 이러한 구조를 직렬화하기 시작했습니다.
그러나 우리는 직렬화하는 동안 Protobuf-net이 매우 큰 인 메모리 버퍼를 생성하고 있음을 확인했습니다. 소스 코드를 살펴보면 버퍼의 전체 길이를 나중에 버퍼의 앞쪽에 써야하기 때문에 전체 내부 버퍼가 플러시되지 않을 수도 있습니다 (전체 List<byte[]>
구조가 작성된 것 같습니다).
이것은 불행하게도 바이트를 chunking하는 작업을 취소하고 결국 메모리 조각화로 인해 OutOfMemoryExceptions를줍니다 (예외는 Protobuf-net이 버퍼를 84k 이상으로 확장하려고 시도 할 때 발생합니다. LOH에 저장하고 우리의 전반적인 프로세스 메모리 사용량은 상당히 적음).
Protobuf-net의 작동 방식에 대한 분석이 정확하다면이 문제를 해결할 수있는 방법이 있습니까?
업데이트
마크의 답변에 따라, 여기에 내가 무엇을 시도했다입니다 :
[ProtoContract]
[ProtoInclude(1, typeof(A), DataFormat = DataFormat.Group)]
public class ABase
{
}
[ProtoContract]
public class A : ABase
{
[ProtoMember(1, DataFormat = DataFormat.Group)]
public B B
{
get;
set;
}
}
[ProtoContract]
public class B
{
[ProtoMember(1, DataFormat = DataFormat.Group)]
public List<byte[]> Data
{
get;
set;
}
}
그런 다음 그것을 직렬화 그러나
var a = new A();
var b = new B();
a.B = b;
b.Data = new List<byte[]>
{
Enumerable.Range(0, 1999).Select(v => (byte)v).ToArray(),
Enumerable.Range(2000, 3999).Select(v => (byte)v).ToArray(),
};
var stream = new MemoryStream();
Serializer.Serialize(stream, a);
을 내가 스틱 경우 중단 점이 ProtoWriter.WriteBytes()
인 경우라고합니다.메서드의 맨 아래로 DemandSpace()
으로 들어가면 writer.flushLock
이 1
이므로 버퍼가 플러시되지 않는 것을 알 수 있습니다.
이 같은베이스상의 또 다른 기본 클래스 작성하는 경우 :
[ProtoContract]
[ProtoInclude(1, typeof(ABase), DataFormat = DataFormat.Group)]
public class ABaseBase
{
}
[ProtoContract]
[ProtoInclude(1, typeof(A), DataFormat = DataFormat.Group)]
public class ABase : ABaseBase
{
}
그런 다음
writer.flushLock
가
DemandSpace()
에서
2
동일합니다.
파생 된 유형과 관련하여 여기에 놓친 분명한 단계가 있다고 생각합니까? (bytes
로 매핑)
빠른 답장을 보내 주셔서 감사합니다. 우리의 데이터 구조에 대한 귀하의 추측은 옳았습니다. A에 대한 참조를 포함하는 모든 속성에 대해 DataFormat을 Group으로 변경해야하며 객체 그래프의 루트까지도 변경해야한다고 말하는 것이 옳은가요? 그리고이 변경은 또한 관련 ProtoInclude 속성에도 있어야합니다. –
@James는 본질적으로 그렇습니다. 음 ... 아마도 모델 레벨의 기본값을 추가해야 할 것입니다! –
DataFormat.Group을 사용하여 문제를 해결하기 위해 시도한 내용으로 내 질문을 업데이트했지만 버퍼를 비우는 데 여전히 문제가 있습니다. 내가 바보가된다면 사과한다. .. –