処理が必要な生データを受信する高性能サーバーがあります。パケットを破棄する次のコードは、数千回実行される度に1回AccessViolationをスローします。私は同じ問題を持つ他の人を見つけることができません。残りの時間は正常に動作します。しかし、アクセス違反は致命的であり、このサービスは不安定になります。C#非同期Array.Copy断続的にアクセス違反を投げる
"Array.Copy"行がアクセス違反を頻繁にスローする理由は何ですか?固定キーワードは、GCがメモリを削除するのを止めるべきですか?
async public static Task<AsyncProcessWebFrameResult> ProcessWebFrame(SocketAsyncEventArgs SocketEvent, byte[] Packet, int BytesCnt)
{
AsyncProcessWebFrameResult Result = new AsyncProcessWebFrameResult() { BytesProcessed = 0, Result = ProcessResults.Failed };
ProtocolCommands? CommandType = null;
int WebFrameSize = Marshal.SizeOf(typeof(WebFrameStruct));
//do we at least a enough bytes for a frame?
if (BytesCnt < WebFrameSize)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: Invalid length.");
Result.Result = ProcessResults.ProtocolError;
Result.BytesProcessed = BytesCnt;
return Result;
}
int StartIdx = 0;
//frame start with SOD?
int BytesToCheck = Math.Min(BytesCnt+2, Packet.Length);
while (StartIdx < BytesToCheck && Packet[StartIdx] != 0xA5)
StartIdx++;
if (StartIdx > 0 && StartIdx < BytesCnt - 1)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: Does not start with SOD. Discarding " + StartIdx +" bytes");
Result = await ProcessWebFrame(SocketEvent, Packet.Skip(StartIdx).ToArray(), BytesCnt - StartIdx);
Result.BytesProcessed += StartIdx;
return Result;
}
else if (StartIdx == BytesCnt-1)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: SOD not found discarding all.");
Result.Result = ProcessResults.ProtocolError;
Result.BytesProcessed = BytesCnt;
return Result;
}
else if (StartIdx != 0)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: SOD not found discarding all.");
Result.Result = ProcessResults.ProtocolError;
Result.BytesProcessed = BytesCnt;
return Result;
}
byte[] Payload = new byte[0];
try
{
unsafe
{
fixed (byte* pFirstByte = &(Packet[0]))
{
WebFrameStruct* pFrame = (WebFrameStruct*)pFirstByte;
//Have we received the whole packet?
if (BytesCnt < WebFrameSize + pFrame->Size)
{
DebugUtils.ConsoleWriteLine(SocketEvent, string.Format("Packet: Packet incomplete. Expected: {0}, Received {1}", pFrame->Size + WebFrameSize, BytesCnt));
Result.Result = ProcessResults.AwaitingMoreData;
return Result;
}
//recognised protocol version?
if (((pFrame->Flags >> 4) & 0xF) != PROTO_VER)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: Invalid protocol version.");
Result.Result = ProcessResults.ProtocolError;
Result.BytesProcessed = 1; //false start of frame, discard SOD
return Result;
}
//We have a valid packet so we can mark the bytes as processed so they get discarded, regardless of the result below.
Result.BytesProcessed = WebFrameSize + (int)pFrame->Size;
//do we have a registered controller for the command type
if (CommandControllers.ContainsKey((ProtocolCommands)pFrame->Type))
{
CommandType = (ProtocolCommands)pFrame->Type;
Array.Resize(ref Payload, (int)pFrame->Size);
if (Payload.Length != (int)pFrame->Size)
DebugUtils.ConsoleWriteLine(SocketEvent, string.Format("Array size incorrect. Is: {0} Should be {1}", Payload.Length, pFrame->Size));
================================================
Array.Copy(Packet, WebFrameSize, Payload, 0, (int)pFrame->Size); <---- this line throws the exception
=================================================
DebugUtils.ConsoleWriteLine(SocketEvent, string.Format("Packet is {0} -> sending to controller ", (ProtocolCommands)pFrame->Type));
}
else
{
DebugUtils.ConsoleWriteLine(SocketEvent, string.Format("Packet: No registered controller for Job {0}.", (ProtocolCommands)pFrame->Type));
Result.Result = ProcessResults.NoController;
return Result;
}
}
}
}
catch (AccessViolationException E)
{
Program.HandleFatalExceptions("", E);
}
return Result;
}
上記の方法は、
await ProcessWebFrame(SocketEvent, RxBuffer.Skip(Offset).ToArray(), RXBufferUsed - Offset);
特定の行== ...この投稿は、私が代わりにこれを使用して考える作ら...と、それは「安全でない」コードの使用を避けるように私はそれが好き==================コードの最後に向かって。 – Karl
eh、 'fixed'はそのアドレスの内容が動かないようにします。スコープ内にある(編集されていてまだ参照されている)オブジェクトは、GCがそれを削除するのを防ぎます。 – BurnsBA
@BurnsBAはコメントに感謝します。しかし、私はそれが上記に影響を与えるとは思わない?あれは正しいですか? – Karl