다음을 통해 공유


복사 및 고정

데이터를 마샬링할 때 interop 마샬러는 마샬링되는 데이터를 복사하거나 고정할 수 있습니다. 데이터를 복사하면 한 메모리 위치의 데이터 복사본이 다른 메모리 위치에 배치됩니다. 다음 그림에서는 값 형식 복사와 관리되는 메모리에서 관리되지 않는 메모리로 참조로 전달된 형식 복사의 차이점을 보여 줍니다.

값 및 참조 형식을 복사하는 방법을 보여 주는 다이어그램

값으로 전달된 메서드 인수는 관리되지 않는 코드에 스택의 값으로 마샬링됩니다. 복사 프로세스가 직접 수행됩니다. 참조로 전달된 인수는 스택에 대한 포인터로 전달됩니다. 참조 형식도 값과 참조로 전달됩니다. 다음 그림과 같이 값으로 전달된 참조 형식은 복사되거나 고정됩니다.

값 전달 및 참조 전달로 이루어진 참조 형식을 보여주는 다이어그램입니다.

고정하면 현재 메모리 위치에 데이터가 일시적으로 잠기므로 공용 언어 런타임의 가비지 수집기에서 데이터를 재배치할 수 없습니다. 마샬러는 데이터를 고정하여 복사 오버헤드를 줄이고 성능을 향상시킵니다. 데이터 형식은 마샬링 프로세스 중에 복사 또는 고정되는지 여부를 결정합니다. 고정은 String와 같은 개체들을 마샬링하는 동안 자동으로 수행되지만, GCHandle 클래스를 사용하여 메모리를 수동으로 고정할 수도 있습니다.

서식이 지정된 Blittable 클래스

형식이 지정된 Blittable 클래스에는 관리되는 메모리와 관리되지 않는 메모리 모두에서 고정 레이아웃(형식 지정) 및 공통 데이터 표현이 있습니다. 이러한 형식에 마샬링이 필요한 경우 힙의 개체에 대한 포인터가 호출 수신자에게 직접 전달됩니다. 호출 수신자는 포인터에서 참조하는 메모리 위치의 내용을 변경할 수 있습니다.

비고

호출 수신자는 매개변수가 Out 또는 In/Out으로 표시된 경우 메모리 내용을 변경할 수 있습니다. 반면, 매개변수가 형식이 지정된 블리터블 형식의 기본값인 In으로 마샬링되도록 설정된 경우 호출 수신자는 내용을 변경하지 않아야 합니다. In 개체를 수정하면 동일한 클래스를 형식 라이브러리로 내보내고 아파트 간 호출에 사용할 때 문제가 발생합니다.

서식이 지정된 Blittable이 아닌 클래스

서식이 지정된 Blittable이 아닌 클래스에는 고정 레이아웃(형식이 지정됨)이 있지만 관리되는 메모리와 관리되지 않는 메모리에서는 데이터 표현이 다릅니다. 데이터는 다음 조건에서 변환이 필요할 수 있습니다.

  • 블리트 가능하지 않은 클래스가 값으로 마샬링될 때, 호출하는 쪽은 데이터 구조의 복사본에 대한 포인터를 받습니다.

  • blittable이 아닌 클래스가 참조로 마샬링되는 경우 호출 부는 데이터 구조 복사본에 대한 포인터의 포인터를 받습니다.

  • 특성이 InAttribute 설정된 경우 이 복사본은 항상 인스턴스의 상태로 초기화되고 필요에 따라 마샬링됩니다.

  • 특성이 OutAttribute 설정된 경우 상태는 항상 반환 시 인스턴스로 다시 복사되고 필요에 따라 마샬링됩니다.

  • InAttributeOutAttribute가 모두 설정된 경우 두 복사본이 모두 필요합니다. 두 특성 중 하나를 생략하면 마샬러는 복사본을 제거하여 최적화할 수 있습니다.

참조 형식

참조 형식은 값 또는 참조로 전달할 수 있습니다. 값으로 전달되면 형식에 대한 포인터가 스택에 전달됩니다. 참조로 전달되면 형식에 대한 포인터에 대한 포인터가 스택에 전달됩니다.

참조 형식에는 다음과 같은 조건부 동작이 있습니다.

  • 참조 형식이 값으로 전달되고 Blittable이 아닌 형식의 멤버가 있는 경우 형식은 두 번 변환됩니다.

    • 인수가 관리되지 않는 쪽에 전달되는 경우

    • 호출에서 돌아올 때.

    불필요하게 복사 및 변환을 방지하기 위해 이러한 형식은 In 매개 변수로 마샬링됩니다. 호출자가 변경한 내용을 보려면 InAttributeOutAttribute 특성을 인수에 명시적으로 적용해야 합니다.

  • 참조 형식이 값으로 전달되고 Blittable 형식의 멤버만 있는 경우 마샬링 중에 고정할 수 있으며 호출자가 형식의 멤버를 변경한 내용은 호출자가 볼 수 있습니다. 이 동작을 원하는 경우 InAttributeOutAttribute 를 명시적으로 적용합니다. 이러한 방향 특성이 없으면 interop 마샬러는 방향 정보를 형식 라이브러리로 내보내지 않으며(기본값은 In으로 내보내기) 이로 인해 COM 아파트 간 마샬링에서 문제가 발생할 수 있습니다.

  • 참조 형식이 참조로 전달되면 기본적으로 In/Out으로 마샬링됩니다.

System.String 및 System.Text.StringBuilder

데이터를 값 또는 참조로 관리되지 않는 코드로 마샬링하는 경우 마샬러는 일반적으로 데이터를 보조 버퍼에 복사하고(복사 중에 문자 집합을 변환할 수 있음) 버퍼에 대한 참조를 호출 수신자에게 전달합니다. 참조가 SysAllocString으로 할당된 BSTR이 아니면 참조는 항상 CoTaskMemAlloc로 할당됩니다.

최적화로서 String 또는 StringBuilder가 값(예: 유니코드 문자열) 기준으로 마샬링되는 경우, 마샬러는 호출 수신자에게 내부 유니코드 버퍼의 관리되는 문자열에 대한 직접 포인터를 전달하여 새 버퍼로 복사하는 것을 피합니다.

주의

문자열이 값으로 전달되면 호출 수신자는 마샬러가 전달한 참조를 변경하지 않아야 합니다. 이렇게 하면 관리 힙이 손상될 수 있습니다.

참조로 System.String 전달되면 마샬러는 호출하기 전에 문자열의 내용을 보조 버퍼에 복사합니다. 그런 다음 호출에서 반환할 때 버퍼의 내용을 새 문자열에 복사합니다. 이 기술을 사용하면 변경할 수 없는 관리되는 문자열이 변경되지 않은 상태로 유지됩니다.

값으로 System.Text.StringBuilder 전달되면 마샬러는 StringBuilder 의 내부 버퍼의 임시 복사본에 대한 참조를 호출자에게 전달합니다. 호출자와 호출자는 버퍼의 크기에 동의해야 합니다. 호출자는 적절한 길이의 StringBuilder 를 만듭니다. 호출 수신자는 버퍼가 오버플로되지 않도록 필요한 예방 조치를 취해야 합니다. StringBuilder 는 값으로 전달된 참조 형식이 기본적으로 매개 변수로 In 전달되는 규칙에 대한 예외입니다. StringBuilder는 항상 In/Out로 전달됩니다.

참고하십시오