Chciałbym wiedzieć, co to jest kopiowanie podczas zapisu i do czego służy? Termin „tablica kopiowania przy zapisie” jest wspominany kilka razy w tutorialach Sun JDK, ale nie rozumiałem, co to znaczy.
źródło
Chciałbym wiedzieć, co to jest kopiowanie podczas zapisu i do czego służy? Termin „tablica kopiowania przy zapisie” jest wspominany kilka razy w tutorialach Sun JDK, ale nie rozumiałem, co to znaczy.
Zamierzałem napisać własne wyjaśnienie, ale ten artykuł w Wikipedii podsumowuje to.
Oto podstawowa koncepcja:
Kopiowanie przy zapisie (czasami określane jako „COW”) to strategia optymalizacji stosowana w programowaniu komputerowym. Podstawową ideą jest to, że jeśli wielu dzwoniących prosi o zasoby, które są początkowo nie do odróżnienia, możesz podać im wskaźniki do tego samego zasobu. Ta funkcja może być utrzymywana do momentu, gdy wywołujący spróbuje zmodyfikować swoją „kopię” zasobu, w którym to momencie tworzona jest prawdziwa prywatna kopia, aby zmiany nie stały się widoczne dla wszystkich innych. Wszystko to dzieje się w sposób przejrzysty dla dzwoniących. Podstawową zaletą jest to, że jeśli dzwoniący nigdy nie wprowadza żadnych modyfikacji, nie ma potrzeby tworzenia kopii prywatnej.
Również tutaj jest zastosowanie powszechnego użycia COW:
Koncepcja COW jest również wykorzystywana do konserwacji natychmiastowych migawek na serwerach baz danych, takich jak Microsoft SQL Server 2005. Błyskawiczne migawki zachowują statyczny widok bazy danych, przechowując przed modyfikacją kopię danych podczas aktualizacji danych. Natychmiastowe migawki są używane do testowania zastosowań lub raportów zależnych od chwili i nie powinny być używane do zastępowania kopii zapasowych.
clone()
do implementacjifork()
- pamięć procesu nadrzędnego jest zabezpieczona dla dziecka.„Kopiuj przy zapisie” oznacza mniej więcej to, co brzmi: każdy ma jedną wspólną kopię tych samych danych, dopóki nie zostaną zapisane , a potem kopia zostanie wykonana. Zwykle kopiowanie przy zapisie służy do rozwiązywania różnego rodzaju problemów związanych z współbieżnością. Na przykład w ZFS bloki danych na dysku są przydzielane do kopiowania przy zapisie; dopóki nie ma zmian, zachowujesz oryginalne bloki; zmiana dotyczyła tylko bloków, na które miała wpływ. Oznacza to, że przydzielono minimalną liczbę nowych bloków.
Zmiany te są również zwykle implementowane w celu transakcyjnym , tj. Mają właściwości ACID . Eliminuje to niektóre problemy ze współbieżnością, ponieważ wtedy masz gwarancję, że wszystkie aktualizacje są atomowe.
źródło
A
. Proces1
,2
,3
,4
każda chcesz zrobić kopię i zacząć czytać ją w „copy on write” system nie jest jeszcze skopiowane wszystko jest jeszcze czytaA
. Teraz proces3
chce wprowadzić zmiany w swojej kopiiA
, proces3
faktycznie wykona kopięA
i utworzy nowy blok danych o nazwieB
. Proces1
,2
,4
nadal odczytu blokA
procesu3
jest odczytuB
.A
powinien tworzyć nową kopię. Jeśli pytasz, co się stanie, jeśli pojawi się zupełnie nowy proces i ulegnie zmianie,A
to moje wyjaśnienie nie jest wystarczająco szczegółowe. Byłoby to specyficzne dla implementacji i wymagałoby wiedzy o tym, jak chcesz, aby reszta implementacji działała, na przykład blokowanie plików \ danych itp.Nie powtórzę tej samej odpowiedzi w przypadku kopiowania przy zapisie. Myślę, że odpowiedź Andrzeja i odpowiedź Charliego już bardzo wyraźnie. Podam przykład ze świata OS, żeby wspomnieć, jak szeroko jest to pojęcie używane.
Możemy użyć
fork()
lubvfork()
stworzyć nowy proces. vfork działa zgodnie z koncepcją kopiowania przy zapisie. Na przykład proces potomny utworzony przez vfork będzie współdzielił dane i segment kodu z procesem nadrzędnym. Przyspiesza to czas rozwidlenia. Oczekuje się, że użyje vfork, jeśli wykonujesz exec, a następnie vfork. Zatem vfork utworzy proces potomny, który będzie współdzielił dane i segment kodu ze swoim rodzicem, ale kiedy wywołasz exec, załaduje obraz nowego pliku wykonywalnego do przestrzeni adresowej procesu potomnego.źródło
vfork
NIE używa COW. W rzeczywistości, jeśli dziecko coś napisze, może to skutkować niezdefiniowanym zachowaniem i nie kopiowaniem stron !! W rzeczywistości można powiedzieć, że jest nieco odwrotnie. COW działa tak, jakbyvfork
coś zostało zmodyfikowane we wspólnej przestrzeni!Aby podać inny przykład, Mercurial używa kopiowania przy zapisie aby klonowanie lokalnych repozytoriów było naprawdę „tanią” operacją.
Zasada jest taka sama, jak w innych przykładach, z tym wyjątkiem, że mówisz o plikach fizycznych zamiast o obiektach w pamięci. Początkowo klon nie jest duplikatem, ale twardym połączeniem z oryginałem. Gdy zmieniasz pliki w klonie, zapisywane są kopie reprezentujące nową wersję.
źródło
Znalazłem ten dobry artykuł o zval w PHP, w którym wspomniano również o COW:
źródło
Kopiowanie przy zapisie to technika zmniejszania wykorzystania pamięci przez kopie zasobów poprzez udostępnianie pamięci do momentu zmodyfikowania jednej z kopii. Innymi słowy, kopie są początkowo kopiami wirtualnymi i stają się rzeczywistymi kopiami dopiero przy pierwszej operacji zapisu, stąd nazwa „kopiuj przy zapisie”.
Poniżej znajduje się implementacja w Pythonie techniki kopiowania przy zapisie przy użyciu wzorca projektowego proxy .
ValueProxy
Obiektu ( proxy ) implementuje technikę kopiowanie przy zapisie poprzez:Value
obiektem ( podmiotem );Value
obiektu z nowym stanem i ponowne wiązanie atrybutu podmiotu na nowy niezmiennyValue
obiekt;ValueProxy
obiektu mającego ten sam atrybut podmiotu, co oryginalnyValueProxy
obiekt.import abc class BaseValue(abc.ABC): @abc.abstractmethod def read(self): raise NotImplementedError @abc.abstractmethod def write(self, data): raise NotImplementedError class Value(BaseValue): def __init__(self, data): self.data = data def read(self): return self.data def write(self, data): pass class ValueProxy(BaseValue): def __init__(self, subject): self.subject = subject def read(self): return self.subject.read() def write(self, data): self.subject = Value(data) def clone(self): return ValueProxy(self.subject) v1 = ValueProxy(Value('foo')) v2 = v1.clone() # shares the immutable Value object between the copies assert v1.subject is v2.subject v2.write('bar') # creates a new immutable Value object with the new state assert v1.subject is not v2.subject
źródło
Jest również używany w Ruby „Enterprise Edition” jako zgrabny sposób oszczędzania pamięci.
źródło
Dobrym przykładem jest Git, który wykorzystuje strategię do przechowywania obiektów blob. Dlaczego używa skrótów? Częściowo dlatego, że są one łatwiejsze do wykonywania różnic, ale także dlatego, że upraszczają optymalizację strategii COW. Kiedy dokonujesz nowego zatwierdzenia z kilkoma zmianami plików, zdecydowana większość obiektów i drzew nie ulegnie zmianie. Dlatego zatwierdzenie, poprzez różne wskaźniki utworzone z hashów, będzie odnosić się do zbioru obiektów, które już istnieją, sprawiając, że przestrzeń magazynowa wymagana do przechowywania całej historii będzie znacznie mniejsza.
źródło
Jest to koncepcja ochrony pamięci. W tym kompilatorze tworzy dodatkową kopię w celu modyfikacji danych w podrzędnym, a te zaktualizowane dane nie odzwierciedlają danych rodziców.
źródło