Trong ứng dụng của chúng tôi, chúng tôi có một số cấu trúc dữ liệu trong số những thứ khác chứa một danh sách các byte (hiện đang được xem là List<byte[]>
). Chúng tôi chunk byte lên bởi vì nếu chúng ta cho phép các mảng byte được đặt trên heap đối tượng lớn sau đó theo thời gian chúng ta bị phân mảnh bộ nhớ.Sử dụng bộ nhớ tuần tự các mảng byte được ghép nối với Protobuf-net
Chúng tôi cũng bắt đầu sử dụng Protobuf-net để tuần tự hóa các cấu trúc này, bằng cách sử dụng DLL tuần tự được tạo riêng của chúng tôi.
Tuy nhiên chúng tôi đã nhận thấy rằng Protobuf-net đang tạo bộ đệm trong bộ nhớ rất lớn trong khi tuần tự hóa. Liếc qua mã nguồn có vẻ như nó không thể tuôn ra bộ đệm bên trong của nó cho đến khi toàn bộ cấu trúc List<byte[]>
đã được viết bởi vì nó cần viết tổng chiều dài ở phía trước của bộ đệm sau đó. Điều này không may làm hỏng công việc của chúng tôi với chunking các byte ở nơi đầu tiên, và cuối cùng cho chúng tôi OutOfMemoryExceptions do phân mảnh bộ nhớ (ngoại lệ xảy ra tại thời điểm Protobuf-net đang cố gắng để mở rộng bộ đệm đến hơn 84k, mà rõ ràng là đặt nó trên LOH, và quá trình sử dụng bộ nhớ tổng thể của chúng tôi là khá thấp).
Nếu phân tích của tôi về cách Protobuf-net hoạt động là chính xác, có cách nào xung quanh vấn đề này không?
Cập nhật
Dựa trên câu trả lời của Marc, đây là những gì tôi đã cố gắng:
[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;
}
}
Sau đó, để serialize nó:
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);
Tuy nhiên nếu tôi dính điểm ngắt tại ProtoWriter.WriteBytes()
nơi nó gọi DemandSpace()
về phía dưới cùng của phương pháp và bước vào DemandSpace()
, tôi có thể thấy rằng bộ đệm không bị xóa bởi vì writer.flushLock
bằng 1
.
Nếu tôi tạo ra một lớp cơ sở cho làm mất thể diện như thế này:
[ProtoContract]
[ProtoInclude(1, typeof(ABase), DataFormat = DataFormat.Group)]
public class ABaseBase
{
}
[ProtoContract]
[ProtoInclude(1, typeof(A), DataFormat = DataFormat.Group)]
public class ABase : ABaseBase
{
}
Sau đó writer.flushLock
bằng 2
trong DemandSpace()
.
Tôi đoán có một bước rõ ràng mà tôi đã bỏ lỡ ở đây để làm với các loại có nguồn gốc?
Cảm ơn bạn đã trả lời nhanh. Dự đoán của bạn về cấu trúc dữ liệu của chúng tôi là chính xác. Liệu tôi có đúng khi nói rằng chúng ta cần phải thay đổi DataFormat thành Group đối với bất kỳ thuộc tính nào có chứa tham chiếu đến A hay không, và vân vân lên đến gốc của đồ thị đối tượng? Và sự thay đổi này cũng cần phải có trên các thuộc tính ProtoInclude có liên quan? –
@James về cơ bản, vâng. Hmmm ... Có lẽ tôi nên thêm một mặc định mô hình cấp cho điều đó! –
Tôi đã cập nhật câu hỏi của mình với nỗ lực của mình khi sử dụng DataFormat.Group để giải quyết vấn đề nhưng tôi vẫn gặp vấn đề trong việc xóa bộ đệm. Xin lỗi nếu tôi là một thằng ngốc .. –