コピーオンライトとは何ですか?


133

コピーオンライトとは何か、それが何に使用されるのか知りたいのですが。「コピーオンライト配列」という用語は、Sun JDKチュートリアルで何度か言及されていますが、それが何を意味するのか理解できませんでした。

回答:


155

私は私自身の説明を書くつもりでしたが、このウィキペディアの記事はそれをかなり要約しています。

基本的な概念は次のとおりです。

コピーオンライト(「COW」と呼ばれることもあります)は、コンピュータープログラミングで使用される最適化戦略です。基本的な考え方は、複数の呼び出し元が最初は区別できないリソースを要求した場合、同じリソースへのポインタを与えることができるということです。この機能は、呼び出し元がリソースの「コピー」を変更しようとするまで維持できます。その時点で、真のプライベートコピーが作成され、変更が他の人に表示されなくなります。これはすべて、発信者に対して透過的に行われます。主な利点は、呼び出し元が変更を行わない場合、プライベートコピーを作成する必要がないことです。

また、COWの一般的な用途のアプリケーションを次に示します。

COWの概念は、Microsoft SQL Server 2005などのデータベースサーバーでのインスタントスナップショットのメンテナンスにも使用されます。インスタントスナップショットは、基になるデータが更新されたときにデータの変更前のコピーを保存することにより、データベースの静的ビューを保持します。インスタントスナップショットは、テスト用途またはモーメント依存のレポートに使用され、バックアップの置き換えには使用しないでください。


通常の配列が使用されるものは何でも...しかし、状況によっては、このタイプの戦略はより最適化された結果をもたらします。
Andrew Flanagan

3
@hhafez:Linuxはclone()実装に使用するときにそれを使用しますfork()-親プロセスのメモリは子のためにCOWされます。
Kerrek SB、2012

@hhafezいくつかのファイルシステムでは、例えば、牛を使用しBTRFSを
ジェレミア2016年

これはSandboxIEのしくみですか?サンドボックスプログラムが何かを上書きしたい場合、サンドボックスはファイルシステム操作を傍受し、ファイルをサンドボックスフォルダーにコピーして、プログラムが元のファイルではなくサンドボックスファイルに書き込むようにします。それはコピーオンライトと呼ばれていますか?
ロニーマシューズ

マージは最終的にどのように行われますか?N個のコピーがある場合、最終的にどのディスクを保存して、たとえばディスクに保存しますか?
SimpleGuy 2018

59

「書き込み時にコピー」とは、多かれ少なかれそれがどのように聞こえるかを意味します。つまり、書き込みが行われるまで誰もが同じデータの単一の共有コピーを持ち、その後コピーが作成されます。通常、コピーオンライトは、同時実行性の問題を解決するために使用されます。ZFS、例えば、ディスク上のデータブロックがコピーオンライトが割り当てられます。変更がない限り、元のブロックを保持します。変更により、影響を受けるブロックのみが変更されました。つまり、新しいブロックの最小数が割り当てられます。

これらの変更は通常、トランザクションに対応するように実装されます。つまり、これらの変更にはACIDプロパティがあります。これにより、すべての更新がアトミックであることが保証されるため、いくつかの同時実行の問題が解消されます。


1
変更した場合、他のユーザーは新しいコピーについてどのように通知されますか?彼らは間違ったデータを見るでしょう。
パウダー366

12
@ powder366-いいえ、変更を加えると、実際にコピーが作成されるため、間違ったデータは表示されません。たとえば、というデータブロックがあるとしAます。プロセスは1234それのコピーを作成し、それを読んで起動するために、各希望は、「コピーオンライト」のシステムには何もコピーされませんまだすべてはまだ読んでいますA。プロセス3はのコピーに変更を加えようとしていますA。プロセス3は実際にのコピーをA作成し、というデータの新しいブロックを作成しますB。プロセスは124まだブロック読んでいるAプロセスが3今読んでいますB
パドラー2016年

1
@A Puddler「A」で変更が行われた場合にどうなるか。すべてのプロセスが更新された情報または古い情報を読み取りますか?
開発者

3
@開発者:変更を加えているプロセスがどれでもA、新しいコピーを作成する必要があります。まったく新しいプロセスが発生し、変更された場合にどうなるかを質問している場合、A私の説明では、そのための十分な詳細はありません。これは実装固有のこと、あなたが仕事に実装の残りをする方法についての知識を必要とする、などのファイル\データのロック、などでしょう
Puddler

10

私はコピーオンライトについて同じ答えを繰り返さないものとします。アンドリューの答えチャーリーの答えはすでに非常にはっきりしていると思います。OSの例を挙げますが、この概念がどの程度広く使用されているかを説明します。

fork()またはvfork()を使用して、新しいプロセスを作成できます。vforkは、コピーオンライトの概念に従います。たとえば、vforkによって作成された子プロセスは、データとコードセグメントを親プロセスと共有します。これにより、分岐時間が短縮されます。execの後にvforkを実行する場合は、vforkを使用することが想定されています。したがって、vforkは、親とデータおよびコードセグメントを共有する子プロセスを作成しますが、execを呼び出すと、子プロセスのアドレス空間に新しい実行可能ファイルのイメージをロードします。


3
「vforkは、コピーオンライトの概念に従います」。この行を変更することを検討してください。vforkCOWを使用しません。実際、子供が何かを書き込んだ場合、未定義の動作が発生し、ページがコピーされない可能性があります。実際には、逆のことがいくらか正しいと言えます。COW vforkは、共有スペースで何かが変更されるまで機能します。
Pavan Manjunath

Pavanに完全に同意します。「vforkはコピーオンライトの概念に従います」という行を削除します。現在、COWはforkで最適化として使用されているため、vforkのように機能し、子プロセスの親のデータのコピーを作成しません(子でexec *のみを呼び出す場合)
Shekhar Kumar

7

別の例を示すと、Mercurialはコピーオンライト使用して、ローカルリポジトリのクローンを本当に「安価な」操作にします。

原則は、メモリ内のオブジェクトではなく物理ファイルについて話していることを除いて、他の例と同じです。最初は、クローンは複製ではなく、オリジナルへのハードリンクです。クローン内のファイルを変更すると、新しいバージョンを表すコピーが書き込まれます。


2

PHPのzvalに関するこの良い記事を見つけました。COWについても触れています。

コピーオンライト(略して「COW」)は、メモリを節約するために設計されたトリックです。ソフトウェアエンジニアリングでより一般的に使用されます。これは、シンボルがすでにzvalを指している場合、シンボルに書き込むときにPHPがメモリをコピーする(または新しいメモリ領域を割り当てる)ことを意味します。


0

Ruby 'Enterprise Edition'でも、メモリを節約するための優れた方法として使用されています。


2
その意味で彼が「に使用された」という意味ではないと思います。
スパイドン、2015年

0

良い例は、ブロブを保存する戦略を使用するGitです。なぜハッシュを使用するのですか?これらは、比較を実行するのが簡単なためですが、COW戦略の最適化をより簡単にするためでもあります。わずかなファイル変更で新しいコミットを行うとき、オブジェクトとツリーの大部分は変更されません。したがって、コミットは、ハッシュで作成されたさまざまなポインターを介して、すでに存在する一連のオブジェクトを参照し、履歴全体を格納するために必要なストレージスペースをはるかに小さくします。


0

メモリ保護の概念です。このコンパイラでは、子のデータを変更する追加のコピーを作成し、この更新されたデータは親のデータに反映されません。


0

以下は、デコレータデザインパターンを使用したコピーオンライト(COW)Python実装です。不変Valueオブジェクトへの参照は、可変CowValueオブジェクト(デコレーター)によって保持されます。CowValueオブジェクトはすべて転送不変に要求読みValue、オブジェクトをし、新しい不変作成することによって、すべての書き込み要求をインターセプトしValue、正しい状態を持つオブジェクトを。CowValueオブジェクトは、浅いが共有できるように、変数間でコピーしなければならないValueオブジェクトを。

import abc
import copy

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 CowValue(BaseValue):
    def __init__(self, data):
        self.value = Value(data)
    def read(self):
        return self.value.read()
    def write(self, data):
        self.value = Value(data)

v = CowValue(1)
w = copy.copy(v)  # shares the immutable Value object
assert v.read() == w.read()
assert id(v.value) == id(w.value)
w.write(2)  # creates a new immutable Value object with the correct state
assert v.read() != w.read()
assert id(v.value) != id(w.value)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.