Udostępnij za pośrednictwem


Kopiowanie i przypinanie

Podczas marshalingu danych międzyoperajnik może kopiować lub przypinać dane, które są ułożone. 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 that shows how value and reference types are copied.

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

Diagram showing reference types passed by value and by reference.

Przypinanie tymczasowo blokuje dane w bieżącej lokalizacji pamięci, dzięki czemu nie zostaną przeniesione przez moduł odśmiecania pamięci środowiska uruchomieniowego języka wspólnego. 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 przypiąć pamięć przy użyciu GCHandle klasy .

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

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 nielittable 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 klasa nielittable jest skierowana przez odwołanie, obiekt wywoływany odbiera wskaźnik do wskaźnika do kopii struktury danych.

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

  • OutAttribute Jeśli atrybut jest ustawiony, stan jest zawsze kopiowany z powrotem do wystąpienia po powrocie, marshalling zgodnie z potrzebami.

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

Typy odwołań

Typy referencyjne mogą być przekazywane według wartości lub odwołania. Po przekazaniu ich przez wartość wskaźnik do typu jest przekazywany na stos. Po przekazaniu przez odwołanie wskaźnik do wskaźnika do typu jest przekazywany na stos.

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

  • Jeśli typ odwołania jest przekazywany przez wartość i ma elementy członkowskie typów niezwiązanych z 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ą rozdzielane jako w parametrach. Aby zobaczyć zmiany wprowadzone przez obiekt wywoływany, należy jawnie zastosować atrybuty InAttribute i OutAttribute .

  • Jeśli typ odwołania jest przekazywany przez wartość i ma tylko elementy członkowskie typów blittable, można go przypiąć podczas marshalingu i wszelkie zmiany wprowadzone w elementach członkowskich typu przez obiekt wywołujący. Jeśli chcesz, aby to zachowanie było jawne, zastosuj atrybuty InAttribute i OutAttribute . Bez tych atrybutów kierunkowych międzyoperacyjny marshaller nie eksportuje informacji kierunkowych do biblioteki typów (eksportuje jako In, co jest ustawieniem domyślnym) i może to spowodować problemy z marshalingiem między apartamentami COM.

  • Jeśli typ odwołania jest przekazywany przez odwołanie, zostanie on domyślnie rozsyłany jako W/Wy.

System.String i System.Text.StringBuilder

Gdy dane są rozdzielane do niezarządzanego kodu według wartości lub przez odwołanie, marshaller zwykle kopiuje dane do buforu pomocniczego (ewentualnie konwertowania zestawów znaków podczas kopiowania) i przekazuje odwołanie do buforu do wywoływanego. Jeśli odwołanie nie jest odwołaniem przydzielonym za pomocą metody SysAllocString, odwołanie jest zawsze przydzielane za pomocą polecenia CoTaskMemAlloc.

W ramach optymalizacji, gdy wartość String lub StringBuilder jest kierowana przez wartość (na przykład ciąg znaków Unicode), marshaller przekazuje wywoływany wskaźnik bezpośredni do zarządzanych ciągów w wewnętrznym buforze Unicode zamiast kopiować go do nowego buforu.

Uwaga

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

Gdy element System.String jest przekazywany przez odwołanie, marshaller kopiuje zawartość ciągu 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 ciąg zarządzany pozostaje niezauważalny.

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. Obiekt wywołujący i wywoływany musi uzgodnić rozmiar buforu. Obiekt wywołujący jest odpowiedzialny za utworzenie obiektu StringBuilder o odpowiedniej długości. Obiekt wywoływany musi podjąć niezbędne środki ostrożności, aby zapewnić, że bufor nie jest przeładowy. StringBuilder jest wyjątkiem od reguły, która domyślnie przekazuje typy referencyjne przekazywane przez wartość jako In parametry. StringBuilder wartość jest zawsze przekazywana jako In/Out.

Zobacz też