C# Protobuf 메모리 0 할당을 서열화하는 방법
정답1:
msg.ToByteArray()
이것은 틀림없이 우리의 요구에 부합되지 않을 것이다
정답2:
using var memoryStream = new MemoryStream();
using var codedOutputStream = new CodedOutputStream(memoryStream);
msg.WriteTo(codedOutputStream);
codedOutputStream.Flush();
memoryStream.ToArray();
이 안에는 memory Stream, coded Output Stream, 그리고 ToArray가 하나의 대상을 만들었고 Memory Stream 내부에byte[] 대상이 하나 더 생겼다.
부적합
정답3:
어떤 이는 네가 Memory Stream에게 byte[] slice를 전달할 수 있다고 한다. Memory Stream이 직접 byte[]를 사용하도록 한다.
var bytes = new byte[msg.CalculateSize()];
using var memoryStream = new MemoryStream();
using var codedOutputStream = new CodedOutputStream(memoryStream);
msg.WriteTo(codedOutputStream);
codedOutputStream.Flush();
이번 소식은 바로 bytes에 서열화되었다. 그러나memory Stream 대상,codec Output Stream 그리고memory Stream 내부의byte[]가 모두 있었다. 나는 대상을 서열화했는데 3개의 쓰레기 대상이 생겼다.
따라서 Coded OutputStream 클래스를 자세히 살펴보십시오.
///
/// Creates a new CodedOutputStream that writes directly to the given /// byte array. If more bytes are written than fit in the array, /// OutOfSpaceException will be thrown. /// public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length) { } ///
/// Creates a new CodedOutputStream that writes directly to the given /// byte array slice. If more bytes are written than fit in the array, /// OutOfSpaceException will be thrown. /// private CodedOutputStream(byte[] buffer, int offset, int length) { this.output = null; this.buffer = buffer; this.position = offset; this.limit = offset + length; leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference }
提供了一个byte[]的构造函数, 但是没提供slice的构造函数, 好在有一个私有的构造函数
答案4:
这边就不写代码了, 大概意思就是通过反射私有构造函数来构造一个CodedOutputStream对象, 来省掉MemoryStream和他内部的byte[]
现在离答案已经比较接近了
那我们的问题是, 能不能连CodedOutputStream也省掉呢?
答案5来了:
经过仔细观察, 发现这个类没有使用Stream的情况下, 就只需要修改buffer, limit, 和position几个成员就行了, 虽然是private成员, 但是C#还是能修改
下来立马实践
delegate void ClearCodedOutputStream(CodedOutputStream stream, byte[] buffer, int offset, int count);
static ClearCodedOutputStream ResetCodedOutputStream;
static CodedOutputStream codedOutputStream = new CodedOutputStream(new byte[10]);
static unsafe void Encode(IMessage msg, byte[] buffer)
{
ResetCodedOutputStream(codedOutputStream, buffer, 0, buffer.Length);
msg.WriteTo(codedOutputStream);
codedOutputStream.Flush();
}
static Action MakeSetter(FieldInfo field)
{
DynamicMethod m = new DynamicMethod(
"setter", typeof(void), new Type[] { typeof(T), typeof(TValue) }, typeof(Program));
ILGenerator cg = m.GetILGenerator();
cg.Emit(OpCodes.Ldarg_0);
cg.Emit(OpCodes.Ldarg_1);
cg.Emit(OpCodes.Stfld, field);
cg.Emit(OpCodes.Ret);
return (Action)m.CreateDelegate(typeof(Action));
}
static void Main(string[] args)
{
var bufferField = typeof(CodedOutputStream).GetField("buffer", BindingFlags.NonPublic | BindingFlags.Instance);
var limitField = typeof(CodedOutputStream).GetField("limit", BindingFlags.NonPublic | BindingFlags.Instance);
var positionField = typeof(CodedOutputStream).GetField("position", BindingFlags.NonPublic | BindingFlags.Instance);
var setLimit = MakeSetterint>(limitField);
var setPosition = MakeSetterint>(positionField);
var setBuffer = MakeSetterbyte[]>(bufferField);
ResetCodedOutputStream = (stream, buffer, offset, length) =>
{
//this.buffer = buffer;
//this.position = offset;
//this.limit = offset + length;
setBuffer(stream, buffer);
setPosition(stream, offset);
setLimit(stream, offset + length);
};
var buffer = new byte[msg.CalculateSize()];
Encode(msg, buffer);
}
이 실례 코드에는 static의 전역 코드인 Coded Output Stream을 사용했는데, 진정으로 사용할 때는 반드시 라인의 안전을 보장해야 한다.
그래서 다음 문제는:
1. CodedOutputStream 객체 스레드의 보안을 보장하는 방법
2. var buffer = new byte[msg.CalculateSize()]를 어떻게 사용하는가;이것도 아껴요.
이 두 문제는 독자에게 생각하도록 남겨 두어라.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.