- PR -

C# インスタンスのアドレスを固定したい

1
投稿者投稿内容
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-12-21 14:29
構造体やクラスのポインタを使っています。通常はポインタを使用するたびにfixedキーワードでインスタンスを局所的に固定しています。けれど、より広域でインスタンスを固定したい場合があります。固定したいのは特定のインスタンスのみなので、GCの機能そのものは常時働き続けるようにしたいです。

特定のインスタンスのみ固定する方法(つまりGCの移動対象から外す)、および移動を再開する方法を教えてください。
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2004-12-22 00:48
こんばんは、meiです。

引用:

ひろしさんの書き込み (2004-12-21 14:29) より:
構造体やクラスのポインタを使っています。通常はポインタを使用するたびにfixedキーワードでインスタンスを局所的に固定しています。けれど、より広域でインスタンスを固定したい場合があります。固定したいのは特定のインスタンスのみなので、GCの機能そのものは常時働き続けるようにしたいです。



クラスのインスタンスに対してfixedはできません。参照型もしくは、参照型を含む型に対してfixedを行うとコンパイルエラーが出ませんでしたか? お望みの動作はC#が対象とするプログラミング領域ではないと思います。(Managed)C++などを使うべきでしょう。Marshal.AllocHGlobalメソッドを使えばGC管理外のメモリは確保できますが、Managedなオブジェクトを生成するような領域としては使えません。なので、オブジェクトではなく純粋なメモリ領域としてUnmanagedな世界とやり取りするしか無いでしょう。
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2004-12-22 12:59
長期間、データを保持し、広いスコープでデータアクセスしたいのであれば、
Singletonのパターンを使うという手もあります。
ただし、クラススコープのオブジェクトが何らかのタイミングでGCされるかも知れないため、完全な代替案とはならないかもしれません。

速度的には劣ってしまいますが、ファイルやDBに保持しておくという方法も考えられます。
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-12-28 23:47
ご回答ありがとうございます。
C#で確保した領域をDMAでアクセスしたいので今回は残念ながらファイルは活用できません。私はVB6→C#へ移行したユーザーでC++の経験が無いので、可能な限りC++は避けたいと考えています。どうしても方法が無ければC++を学ぶしかないのですが…。

試していないのですが、専用のThreadを作成し、fixedのスコープの中でで必要な期間だけThreadStateをSuspendさせるというのは良い方法でしょうか?
(問題があるような気がしますが…)
_________________
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2004-12-29 01:20
引用:

試していないのですが、専用のThreadを作成し、fixedのスコープの中でで必要な期間だけThreadStateをSuspendさせるというのは良い方法でしょうか?



GC を阻害するのはよくないです。

引用:

C#で確保した領域をDMAでアクセスしたい



なら、Marshal.AllocHGlobal() した領域を使えばいいんじゃないでしょうか。

_________________
// 渋木宏明 (Hiroaki SHIBUKI)
// http://hidori.jp/
// Microsoft MVP for Visual C#
//
// @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/
ひろし
ぬし
会議室デビュー日: 2002/09/16
投稿数: 390
お住まい・勤務地: 兵庫県
投稿日時: 2004-12-29 16:42
ご回答ありがとうございます。
Marshalクラスについていくつか分からない点があります。

Q1.AllocHGlobal()とAllocCoTaskMem()の違いは?

Q2.Marshal.AllocHGlobal()あるいはMarshal.AllocCoTaskMem()で確保された領域は、明示的にFreeHGlobal()あるいはFreeCoTaskMem()を実行するまで(永久に)固定領域が確保されつづけると考えて正しいでしょうか?

(Q3.Q4はある意味Q2と同じ質問ですが)

Q3.Marshal.AllocHGlobal()あるいはMarshal.AllocCoTaskMem()とひもづいたポインタあるいはIntPtrがスコープから外れても領域は確保されつづけるのでしょうか?また、

Q4.アプリケーションがFreeHGlobal()あるいはFreeCoTaskMem()を実行しないで終了してしまった場合、確保された領域は宙に浮いたまま残ってしまうのでしょうか?(メモリーリーク)

Q5.(Q4が真である場合)アプリケーションに予期せぬエラーが発生しても確実にFreeHGlobal()あるいはFreeCoTaskMem()が実行される良い工夫はあるでしょうか?例えば領域を操作するための専用クラスを作成しておいて、Dispose()をoverrideしてFreeHGlobal()あるいはFreeCoTaskMem()を仕込めばOKでしょうか。

宜しくお願いします。
_________________
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2004-12-29 17:22
引用:

Q1.AllocHGlobal()とAllocCoTaskMem()の違いは?



ヘルプにも説明があるはずですが、内部で呼び出している API の違いです。

AllocHGlobal() は GlobalAlloc() API を、AllocCoTaskMem() は CoTaskMemAlloc() API をそれぞれ内部で呼び出しています。

引用:

Q2.Marshal.AllocHGlobal()あるいはMarshal.AllocCoTaskMem()で確保された領域は、明示的にFreeHGlobal()あるいはFreeCoTaskMem()を実行するまで(永久に)固定領域が確保されつづけると考えて正しいでしょうか?



プロセスのアドレス空間内でのアドレスは固定されています。

引用:

Q3.Marshal.AllocHGlobal()あるいはMarshal.AllocCoTaskMem()とひもづいたポインタあるいはIntPtrがスコープから外れても領域は確保されつづけるのでしょうか?
また、

Q4.アプリケーションがFreeHGlobal()あるいはFreeCoTaskMem()を実行しないで終了してしまった場合、確保された領域は宙に浮いたまま残ってしまうのでしょうか?
(メモリーリーク)



GC とは無関係なメモリ確保ですから、参照を失っても自動的に改修されることはありません。ほったらかして置けばリークします。

引用:

Q5.(Q4が真である場合)アプリケーションに予期せぬエラーが発生しても確実にFreeHGlobal()あるいはFreeCoTaskMem()が実行される良い工夫はあるでしょうか?



シナリオ次第なんでなんとも。

[quote]
例えば領域を操作するための専用クラスを作成しておいて、Dispose()をoverrideしてFreeHGlobal()あるいはFreeCoTaskMem()を仕込めばOKでしょうか。
[quote]

なんてのもひとつの方法ではありますね。

_________________
// 渋木宏明 (Hiroaki SHIBUKI)
// http://hidori.jp/
// Microsoft MVP for Visual C#
//
// @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/
1

スキルアップ/キャリアアップ(JOB@IT)