11

ここでそれについて読んでください

そのようなインターフェイスのバリエーションを実装する必要があります。たとえば、管理するための大きなメモリ空間が与えられているとします。そこには getmem(size) および free(ブロックへのポインタ) 関数があり、free(ブロックへのポインタ) が実際に解放できることを確認する必要があります。そのブロックを使用するすべてのプロセスがそれを使用して完了した場合にのみ、メモリ。

私が考えていたのは、Collectable構造体をブロックへのポインタ、そのサイズ、およびそれを使用するプロセスとして定義することです。次に、Collectable構造体インスタンスを初めて使用するプロセスが明示的にカウントをインクリメントする必要があるときはいつでも、プロセスがfree()それを実行するたびに、カウントがデクリメントされます。

このアプローチの問題は、すべてのプロセスがそのインターフェイスに応答し、明示的に機能させる必要があることです。収集可能なポインターをインスタンスに割り当てるときはいつでも、プロセスはそのカウンターを明示的に含める必要がありますが、これは私を満足させません。これがすべての割り当てで暗黙的に発生するようにマクロを作成しますか?

私はしばらくこの問題にアプローチする方法を探しているので、他のアプローチやアイデアは素晴らしいでしょう...

編集:上記のアプローチは、見栄えが悪いだけでなく、実行中のプロセスのコードがカウントの更新を気にかけているとは思えないため、私を満足させません。プロセスのコードを変更せずに確実に完了する方法が必要です...

4

4 に答える 4

6

参照カウントの初期の問題は、コードをカスタム malloc / free 実装に入れることで最初の参照をカウントするのは比較的簡単ですが、最初の受信者がそのアドレスを他の人に渡すかどうかを判断するのはかなり難しいことです。

C には代入演算子をオーバーライドする (新しい参照をカウントする) 機能がないため、基本的に限られた数のオプションしか残されていません。代入をオーバーライドできる可能性がある唯一のものは、参照カウント値のインクリメントをインライン化するものに代入を書き換える機能があるため、macrodef です。

したがって、次のようなマクロを「展開」する必要があります

a = b;

の中へ

if (b is a pointer) { // this might be optional, if lookupReference does this work
  struct ref_record* ref_r = lookupReference(b);
  if (ref_r) {
    ref_r->count++;
  } else {
    // error
  } 
}
a = b;

本当の秘訣は、代入を識別できるマクロを作成し、他の望ましくない副作用を導入することなくコードをきれいに挿入することです。macrodef は完全な言語ではないため、マッチングが不可能になる問題が発生する可能性があります。

(ハンマーの使い方を学ぶ釘を見るというジョークは、ここで興味深い類似点を持っていますが、ハンマーしか持っていない場合は、すべてを釘にする方法を学んだほうがよいということを除いて).

他のオプション (おそらくもっと正気かもしれませんが、そうでないかもしれません) は、malloc によって割り当てられたすべてのアドレス値を追跡し、プログラムのスタックとヒープをスキャンして一致するアドレスを探すことです。一致する場合は、有効なポインターが見つかった可能性があります。または、幸運のエンコーディングを含む文字列が見つかった可能性があります。ただし、一致しない場合は、アドレスを解放できます。元のアドレスから計算されたアドレス + オフセットを格納していない場合。(おそらく、そのようなオフセットを検出するマクロ定義が可能で、同じブロックのスキャンでオフセットを複数のアドレスとして追加できます)

最終的には、参照を返す (アドレスのふりをする) 参照システムを構築しない限り、絶対確実な解決策はありません。本当のアドレスを隠しています。このようなソリューションの欠点は、アドレスを処理するたびにライブラリ インターフェイスを使用する必要があることです。これには、配列内の「次の」要素などが含まれます。あまり C に似ているわけではありませんが、Java がその参照に対して行うことのかなり良い概算です。

于 2012-05-15T21:13:33.673 に答える
5

やや真面目な答え

#include "Python.h"

Python には優れた参照カウント メモリ マネージャーがあります。宿題ではなく、実稼働コードでこれを実際に行う必要がある場合は、Python オブジェクト システムを C プログラムに埋め込むことを検討します。これにより、C プログラムを Python でもスクリプト化できるようになります。興味がある場合は、Python C API ドキュメントを参照してください。

于 2012-05-15T21:27:37.103 に答える
2

このような C のシステムには、プログラマー側である程度の規律が必要ですが ...

所有権の観点から考える必要があります。参照を保持するものはすべて所有者であり、参照を保持するオブジェクトを追跡する必要があります (リストなどを使用)。参照を保持しているモノが破棄されると、参照されたオブジェクトのリストをループし、それらの参照カウンターをデクリメントし、ゼロの場合はそれらを順番に破棄する必要があります。

関数は所有者でもあり、参照されるオブジェクトを追跡する必要があります。たとえば、関数の開始時にリストを設定し、戻るときにそれをループします。

そのため、オブジェクトを新しい所有者に譲渡または共有する必要がある状況を判断し、所有オブジェクトを所有オブジェクトの参照オブジェクトのリストに追加または削除するマクロ/関数で対応する状況をラップする必要があります (それに応じて参照カウンターを調整します)。

最後に、スタック上のオブジェクト/ポインターから到達できなくなったオブジェクトをチェックして、何らかの方法で循環参照に対処する必要があります。これは、マーク アンド スイープ ガベージ コレクション メカニズムを使用して行うことができます。

于 2012-05-15T22:30:33.093 に答える
0

I don't think you can do it automatically without overridable destructors/constructors. You can look at HDF5 ref counting but those require explicit calls in C:

http://www.hdfgroup.org/HDF5/doc/RM/RM_H5I.html

于 2012-05-15T21:08:54.830 に答える