Udostępnij za pośrednictwem


Kopiowanie i przypinanie

Podczas marshalingu danych, marshaler interoperacyjny może kopiować lub przypinać dane podczas marshalingu. Kopiowanie danych powoduje umieszczenie kopii danych z jednej lokalizacji pamięci w innej lokalizacji pamięci. Na poniższej ilustracji przedstawiono różnice między kopiowaniem typu wartości a kopiowaniem typu przekazanego przez odwołanie z zarządzanej do niezarządzanej pamięci.

Diagram przedstawiający sposób kopiowania wartości i typów odwołań.

Argumenty metody przekazywane przez wartość są przekazywane do niezarządzanego kodu jako wartości na stosie. Proces kopiowania jest bezpośredni. Argumenty przekazywane przez odwołanie są przekazywane jako wskaźniki na stosie. Typy referencyjne mogą być przekazywane zarówno przez wartość, jak i przez odwołanie. Jak pokazano na poniższej ilustracji, typy referencyjne przekazywane przez wartość są kopiowane lub przypięte:

Diagram przedstawiający typy referencyjne przekazywane przez wartość i przez referencję.

Przypinanie tymczasowo blokuje dane w ich bieżącej lokalizacji pamięci, uniemożliwiając ich przeniesienie przez garbage collector środowiska uruchomieniowego języka wspólnego (Common Language Runtime). Marshaller przypina dane w celu zmniejszenia nakładu pracy związanego z kopiowaniem i zwiększaniem wydajności. Typ danych określa, czy jest kopiowany, czy przypięty podczas procesu marshallingu. Przypinanie jest wykonywane automatycznie podczas marshalingu dla obiektów, takich jak String, ale można również ręcznie przeprowadzać przypięcie pamięci przy użyciu klasy GCHandle.

Sformatowane klasy Blittable

Sformatowane klasy blittable mają stały układ (sformatowany) i wspólną reprezentację danych zarówno w pamięci zarządzanej, jak i niezarządzanej. Gdy te typy wymagają marshallingu, wskaźnik do obiektu w stercie jest przekazywany bezpośrednio do obiektu wywoływanego. Obiekt wywoływany może zmienić zawartość lokalizacji pamięci przywoływanej przez wskaźnik.

Uwaga / Notatka

Obiekt wywoływany może zmienić zawartość pamięci, jeśli parametr jest oznaczony jako Out lub In/Out. Natomiast obiekt wywoływany powinien unikać zmieniania zawartości, gdy parametr jest ustawiony na marshaling jako In, który jest domyślnym ustawieniem dla sformatowanych typów blittable. Modyfikowanie obiektu In generuje problemy, gdy ta sama klasa jest eksportowana do biblioteki typów i używana do wykonywania wywołań między apartamentami.

Sformatowane klasy inne niż Blittable

Sformatowane klasy non-blittable mają stały układ (sformatowany), ale reprezentacja danych różni się w pamięci zarządzanej i niezarządzanej. Dane mogą wymagać przekształcenia w następujących warunkach:

  • Jeśli klasa nielittable jest określana według wartości, obiekt wywoływany otrzymuje wskaźnik do kopii struktury danych.

  • Jeśli niemieszalna klasa jest przekazywana przez referencję, odbiorca odbiera wskaźnik do wskaźnika do kopii struktury danych.

  • Jeśli atrybut InAttribute jest ustawiony, ta kopia jest zawsze inicjowana ze stanem wystąpienia, wykonując marshalling zgodnie z potrzebami.

  • OutAttribute Jeśli atrybut jest ustawiony, stan jest zawsze kopiowany z powrotem do wystąpienia po zakończeniu działania, z wykonywaniem marshallingu według potrzeb.

  • Jeśli ustawiono zarówno InAttribute, jak i OutAttribute, obie kopie są wymagane. Jeśli którykolwiek z atrybutów zostanie pominięty, marshaller może zoptymalizować, eliminując którąkolwiek z kopii.

Typy odwołań

Typy referencyjne mogą być przekazywane przez wartość lub przez odwołanie. Gdy są przekazywane przez wartość, wskaźnik do typu jest umieszczany na stosie. Gdy przekazuje się przez odwołanie, wskaźnik do wskaźnika do typu jest umieszczany na stosie.

Typy referencyjne mają następujące zachowanie warunkowe:

  • Jeśli typ odwołania jest przekazywany przez wartość i ma elementy nie będące typami blittable, typy są konwertowane dwa razy.

    • Po przekazaniu argumentu do niezarządzanej strony.

    • Po powrocie z połączenia.

    Aby uniknąć niepotrzebnego kopiowania i konwersji, te typy są przekazywane jako parametry wejściowe. W celu umożliwienia obiektowi wywołującemu zobaczenia zmian wprowadzonych przez obiekt wywoływany, należy jawnie zastosować atrybuty InAttribute oraz OutAttribute do argumentu.

  • Jeśli typ odwołania jest przekazywany przez wartość i ma tylko elementy składowe typów blittable, można go zablokować podczas marshalingu, a wszelkie zmiany wprowadzone przez obiekt wywołujący w elementach składowych typu są widoczne dla obiektu wywołującego. Jeśli chcesz, aby to zachowanie było jawne, zastosuj atrybuty InAttribute i OutAttribute . Bez tych atrybutów kierunkowych, marshaler międzyoperacyjny nie eksportuje informacji kierunkowych do biblioteki typów (eksportuje jako In, co jest wartością domyślną) i może to spowodować problemy z marshalingiem między komponentami apartamentowymi COM.

  • Jeśli typ odwołania jest przekazywany jako odwołanie, zostanie on domyślnie obsługiwany jako Wejście/Wyjście.

System.String i System.Text.StringBuilder

Gdy dane są przesyłane do niezarządzanego kodu według wartości lub przez odwołanie, marshaller zwykle kopiuje dane do buforu pomocniczego (ewentualna konwersja zestawów znaków podczas kopiowania) i przekazuje odwołanie do buforu do odbiorcy. Jeśli referencja nie jest referencją przydzieloną za pomocą metody SysAllocString, referencja jest zawsze alokowana za pomocą CoTaskMemAlloc.

Dla optymalizacji wydajności, gdy wartość String lub StringBuilder jest przetwarzana jako wartość (na przykład ciąg znaków Unicode), marshaller przekazuje wywoływanemu bezpośredni wskaźnik do zarządzanych ciągów znaków w wewnętrznym buforze Unicode zamiast kopiowania ich do nowego buforu.

Ostrzeżenie

Gdy ciąg znakowy jest przekazywany przez wartość, odbiorca wywołania nigdy nie może zmieniać odwołania przekazanego przez marshaller. Może to spowodować uszkodzenie zarządzanej sterty.

Gdy element System.String jest przekazywany przez referencję, marshaller kopiuje zawartość ciągu znaków do buforu pomocniczego przed wykonaniem wywołania. Następnie kopiuje zawartość buforu do nowego ciągu po powrocie z wywołania. Ta technika gwarantuje, że niezmienny zarządzany ciąg pozostaje niezmieniony.

Gdy element System.Text.StringBuilder jest przekazywany przez wartość, marshaller przekazuje odwołanie do tymczasowej kopii wewnętrznego buforu StringBuilder do obiektu wywołującego. Dzwoniący i odbierający muszą uzgodnić rozmiar buforu. Obiekt wywołujący jest odpowiedzialny za utworzenie obiektu StringBuilder o odpowiedniej długości. Odbiorca wywołania musi podjąć niezbędne środki ostrożności, aby bufor nie został przepełniony. StringBuilder jest wyjątkiem od reguły, że typy referencyjne przekazywane przez wartość są domyślnie przekazywane jako parametry. StringBuilder jest zawsze przekazywany jako In/Out.

Zobacz także