문제

나는 일부를 할당하는 관리되지 않는 메모리에서 내을 통해 응용 프로그램 Marshal.AllocHGlobal.나는 그때를 복사하면 설정의 바이트하는이 위치 및 변환하는 결과의 세그먼트 메모리 struct 기 전에 메모리를 해제시를 통해 Marshal.FreeHGlobal.

여기방법:

public static T Deserialize<T>(byte[] messageBytes, int start, int length)
    where T : struct
{
    if (start + length > messageBytes.Length)
        throw new ArgumentOutOfRangeException();

    int typeSize = Marshal.SizeOf(typeof(T));
    int bytesToCopy = Math.Min(typeSize, length);

    IntPtr targetBytes = Marshal.AllocHGlobal(typeSize);
    Marshal.Copy(messageBytes, start, targetBytes, bytesToCopy);

    if (length < typeSize)
    {
        // Zero out additional bytes at the end of the struct
    }

    T item = (T)Marshal.PtrToStructure(targetBytes, typeof(T));
    Marshal.FreeHGlobal(targetBytes);
    return item;
}

이 작품은 대부분의 경우,그러나이 있을 경우 적은 바이트의 크기보다 struct 에 필요한 다음 임의의 값이 할당되지막 필드(이용 LayoutKind.Sequential 대상 구조체).고 싶로 이러한 거 필드를 효율적으로 가능합니다.

컨텍스트에 대해,이 코드가 나열 고주파 멀티캐스트 전송된 메시지에서는 C++리눅스에서.

여기에 실패 테스트를 경우:

// Give only one byte, which is too few for the struct
var s3 = MessageSerializer.Deserialize<S3>(new[] { (byte)0x21 });
Assert.AreEqual(0x21, s3.Byte);
Assert.AreEqual(0x0000, s3.Int); // hanging field should be zero, but isn't

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
private struct S3
{
    public byte Byte;
    public int Int;
}

이 테스트를 반복적으로 원인이 두 번째 주장 실패와 다른 값을 각각의 시간입니다.


편집

에서 끝 사용 leppie 의 제안unsafestackalloc.이에 할당된 바이트 배열로 필요에 따라 처리량을 향상 사이에서 50%and100%,에 따라 메시지 크기(큰 메시지를 보았다 더 큰 이익).

최종 방법을 끝났을 닮은:

public static T Deserialize<T>(byte[] messageBytes, int startIndex, int length)
    where T : struct
{
    if (length <= 0)
        throw new ArgumentOutOfRangeException("length", length, "Must be greater than zero.");
    if (startIndex < 0)
        throw new ArgumentOutOfRangeException("startIndex", startIndex, "Must be greater than or equal to zero.");
    if (startIndex + length > messageBytes.Length)
        throw new ArgumentOutOfRangeException("length", length, "startIndex + length must be <= messageBytes.Length");

    int typeSize = Marshal.SizeOf(typeof(T));
    unsafe
    {
        byte* basePtr = stackalloc byte[typeSize];
        byte* b = basePtr;
        int end = startIndex + Math.Min(length, typeSize);
        for (int srcPos = startIndex; srcPos < end; srcPos++)
            *b++ = messageBytes[srcPos];
        return (T)Marshal.PtrToStructure(new IntPtr(basePtr), typeof(T));
    }   
}

불행하게도 이전 호출이 필요합 Marshal.PtrToStructure 변환하는 바이트를 대상으로 형식입니다.

도움이 되었습니까?

해결책

왜 그냥 여부 확인 start + lengthtypesize?

BTW:나는 그냥 가 unsafe 여기에 그 사용을 위한 루프로 추가 메모리입니다.

는 너무 당신의 혜택 사용 stackalloc 는 훨씬 더 안전하고 빠르게 보다 AllocGlobal.

다른 팁

[DllImport("kernel32.dll")]
static extern void RtlZeroMemory(IntPtr dst, int length);
...
RtlZeroMemory(targetBytes, typeSize);

이에서 잘 작동합니다 윈도우:

namespace KernelPInvoke
{
    /// <summary>
    /// Implements some of the C functions declared in string.h
    /// </summary>
    public static class MemoryWrapper
    {
        [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
        static extern void CopyMemory(IntPtr destination, IntPtr source, uint length);

        [DllImport("kernel32.dll", EntryPoint = "MoveMemory", SetLastError = false)]
        static extern void MoveMemory(IntPtr destination, IntPtr source, uint length);

        [DllImport("kernel32.dll", EntryPoint = "RtlFillMemory", SetLastError = false)]
        static extern void FillMemory(IntPtr destination, uint length, byte fill);
    }

    var ptr = Marshal.AllocHGlobal(size);
    try
    {
        MemoryWrapper.FillMemory(ptr, size, 0);
        // further work...
    }
    finally
    {
        Marshal.FreeHGlobal(ptr);
    }
}

Yes 존 Seigel 말할 수 있습 제로 그것을 사용하여 보안관.WriteByte

다음 예에서 나는 제로 하기 전에 버퍼에 복사하는 구조체.

if (start + length > messageBytes.Length) 
    throw new ArgumentOutOfRangeException();   
int typeSize = Marshal.SizeOf(typeof(T));    
int bytesToCopy = Math.Min(typeSize, length);   
IntPtr targetBytes = Marshal.AllocHGlobal(typeSize);  
//zero out buffer
for(int i=0; i < typeSize; i++)
{
    Marshal.WriteByte(targetBytes, i, 0);
}
Marshal.Copy(messageBytes, start, targetBytes, bytesToCopy); 

나는 해본 적이 없는 물건 C#기 전에,그러나 내가 발견한 마샬.WriteByte(IntPtr,Int32,Byte)에 MSDN.Try 습니다.

for(int i=0; i < buffSize / 8; i += 8 )
{
    Marshal.WriteInt64(buffer, i, 0x00);
}

for(int i= buffSize % 8 ; i < -1 ; i-- )
{
    Marshal.WriteByte (buffer, buffSize - i, 0x00);
}

나는 당신이 발견 할 것이다 몇 배 더 빠르게 사용하는 64 비트 라이 8 비트 라는(당신은 아직도에 대한 필요는 마지막 몇 바이트).

내가 생각하는 가장 좋은 방법을 제 밖으로 버퍼는 이것을 원하지 않는 경우,또는 수 없습니다 다른 길을 갈:

for(int i=0; i<buffSize; i++)
{
    Marshal.WriteByte(buffer, i, 0x00);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top