2013-05-12 2 views
1

다음 코드에서는 File 객체의 모든 Block 객체를 전달하고 BitConverted 기반 직렬화를 수행합니다. 어떤 경우에는 OutOfMemory 예외가 있습니다. 최적화 할 방법이 있습니까?사용자 정의 직렬화를 사용할 때 OutOfMemory 예외

File.Serialze();

public byte[] Serialize() 
{ 
    byte[] bytes = new byte[Blocks.Count * Block.Size]; 

    for (int i = 0; i < Blocks.Count; i++) 
    { 
     Block block = Blocks[i]; 
     Buffer.BlockCopy(block.Serialize(), 0, bytes, i * Block.Size, Block.Size); 
    } 
    return bytes; 
} 

Block.Serialize()

public byte[] Serialize() 
{ 
    byte[] bytes = new byte[Size]; 

    Buffer.BlockCopy(BitConverter.GetBytes(fid), 0, bytes, 0, sizeof(long)); 
    Buffer.BlockCopy(BitConverter.GetBytes(bid), 0, bytes, sizeof(long), sizeof(long)); 
    Buffer.BlockCopy(BitConverter.GetBytes(oid), 0, bytes, sizeof(long) * 2, sizeof(long)); 
    Buffer.BlockCopy(BitConverter.GetBytes(iid), 0, bytes, sizeof(long) * 3, sizeof(long)); 
    Buffer.BlockCopy(BitConverter.GetBytes(did), 0, bytes, sizeof(long) * 4, sizeof(long)); 

    return bytes; 
} 

대신 바이트 []의 MemoryStream을하고 BitConverter.GetBytes 대신 편이() 메소드

File.Serialize()

public MemoryStream Serialize() 
{ 
    MemoryStream fileMemoryStream = new MemoryStream(Blocks.Count * Block.Size); 
    foreach (Block block in Blocks) 
    { 
     using (MemoryStream blockMemoryStream = block.Serialize()) 
     { 
      blockMemoryStream.WriteTo(fileMemoryStream); 
     } 
    } 

    return fileMemoryStream; 
} 

Block.Serialize()

public MemoryStream Serialize() 
{ 
    MemoryStream memoryStream = new MemoryStream(Size); 

    memoryStream.Write(ConvertLongToByteArray(fid), 0, sizeof(long)); 
    memoryStream.Write(ConvertLongToByteArray(bid), 0, sizeof(long)); 
    memoryStream.Write(ConvertLongToByteArray(oid), 0, sizeof(long)); 
    memoryStream.Write(ConvertLongToByteArray(iid), 0, sizeof(long)); 
    memoryStream.Write(ConvertLongToByteArray(did), 0, sizeof(long)); 

    return memoryStream; 
} 

    private byte[] ConvertLongToByteArray(long number) 
    { 
     byte[] bytes = new byte[8]; 
     bytes[7] = (byte)((number >> 56) & 0xFF); 
     bytes[6] = (byte)((number >> 48) & 0xFF); 
     bytes[5] = (byte)((number >> 40) & 0XFF); 
     bytes[4] = (byte)((number >> 32) & 0XFF); 
     bytes[3] = (byte)((number >> 24) & 0xFF); 
     bytes[2] = (byte)((number >> 16) & 0xFF); 
     bytes[1] = (byte)((number >> 8) & 0XFF); 
     bytes[0] = (byte)((number & 0XFF)); 

     return bytes; 
    } 

답변

1

첫 번째 질문은 : 카운트와 크기는 무엇입니까? 그것들 (곱해질 때)이 크다면, 그것은 기억을 씹을 것입니다. 물론 큰 버퍼로 직렬화하면 항상 문제가 발생할 것입니다. 스트림에 직렬화하는 기술을 살펴보면 중간 크기의 단일 버퍼를 사용할 수 있습니다. 어쩌면 각각의 "블록"을 개별적으로 직렬화하고 스트림으로 플러시 한 다음 적당히 크기가 같은 동일한 버퍼를 다시 사용할 수 있습니다. 개인적으로 필자는 불필요한 "블록"을 피하려고 노력합니다. 다른 기술은 버퍼링 된 스트림으로 직렬화하여 기본 스트림으로 플러시 할시기를 결정하는 것입니다.

마지막으로 BitConverter가 byte []를 만들려고한다는 사실은 항상 실망 스럽습니다. 그 API를 작성한 사람은 단호한 대화가 필요합니다. 버퍼와 오프셋을 취하여 기존 버퍼에 쓰는 API를 사용하는 것이 적절한 기술이었습니다. 할당이 훨씬 적습니다. 나는이 모든 (명백하게 수명이 짧은) 할당없이 쓰는 방법을 살펴볼 것을 권합니다. 이는 int/long 등 (쉬프트 연산 만 사용)은 쉽지만 이중 등의 경우 안전하지 않은 코드 또는 공용 구조체가 필요할 것입니다.

+0

Marc Gravell, 먼저 감사의 말을 들어 주셔서 감사합니다. * 크기는 대용량입니다. 저는 byte [] 대신 MemoryStream을 구현하고 BitConverter.GetBytes() 대신 Shift를 구현했습니다. 같은 문제가 다시 나타납니다. 내 구현을 추가했습니다, 아마도 거기에 몇 가지 문제가있어. – eugeneK

+0

@eugeneK 폭발 할 때 스택 트레이스는 무엇입니까? 만약 데이터가 * large *이면,'MemoryStream'은 여전히 ​​같은 문제를 겪을 것입니다 : 당신은 메모리의 외부 *를 직렬화해야 할 수도 있습니다. 어떤 종류의 크기를 기대하십니까? 대신 파일에 직렬화 해보십시오. –

+0

File.Size가 8K에서 20MB 사이임 – eugeneK