C#でunsafeキーワードを使用してポインターを使用すると、どのような結果(正/負)になりますか? たとえば、ガベージ コレクションはどうなるか、パフォーマンスの向上/低下は何か、他の言語と比較してパフォーマンスの向上/低下はどのようなものか、手動メモリ管理はどのような危険性があるか、どのような状況でこの言語を使用することが本当に正当化されるか機能、コンパイルに時間がかかります...?
4 に答える
As already mentioned by Conrad, there are some situations where unsafe access to memory in C# is useful. There are not as many of them, but there are some:
Manipulating with
Bitmap
is almost a typical example where you need some additional performance that you can get by usingunsafe
.Interoperability with older API (such as WinAPI or native C/C++ DLLs) is another area where
unsafe
can be quite useful - for example you may want to call a function that takes/returns an unmanaged pointer.
On the other hand, you can write most of the things using Marshall
class, which hides many of the unsafe operations inside method calls. This will be a bit slower, but it is an option if you want to avoid using unsafe
(or if you're using VB.NET which doesn't have unsafe
)
Positive consequences:
So, the main positive consequences of the existence of unsafe
in C# is that you can write some code more easily (interoperability) and you can write some code more efficiently (manipulating with bitmap or maybe some heavy numeric calculations using arrays - although, I'm not so sure about the second one).
Negative consequences: Of course, there is some price that you have to pay for using unsafe
:
Non-verifiable code: C# code that is written using the
unsafe
features becomes non-verifiable, which means that the your code could compromise the runtime in any way. This isn't a big problem in a full-trust scenario (e.g. unrestricted desktop app) - you just don't have all the nice .NET CLR guarantees. However, you cannot run the application in a restricted enviornment such as public web hosting, Silverlight or partial trust (e.g. application running from network).Garbage collector also needs to be careful when you use
unsafe
. GC is usually allowed to relocate objects on the managed heap (to keep the memory defragmented). When you take a pointer to some object, you need to use thefixed
keyword to tell the GC that it cannot move the object until you finish (which could probably affect the performance of garbage collection - but of course, depending on the exact scenario).
My guess that if C# didn't have to interoperate with older code, it probably wouldn't support unsafe
(and research projects like Singularity that attempt to create more verifiable operating system based on managed languages definitely disallow usnsafe code). However, in the real-world, unsafe
is useful in some (rare) cases.
使用する価値のある状況を紹介できます。
ピクセルごとにビットマップを生成する必要があります。Drawing.Bitmap.SetPixel()
遅すぎる。Array
そこで、ビットマップ データの独自のマネージを作成し、 forunsafe
を取得するIntPtr
ために使用しますBitmap.Bitmap( Int32, Int32, Int32, PixelFormat, IntPtr)
。
Professional C# 2008 を引用するには:
「ポインターを使用する主な理由は次の 2 つです。
- 下位互換性- .NET ランタイムによって提供されるすべての機能にもかかわらず、ネイティブ Windows API 関数を呼び出すことは依然として可能であり、一部の操作では、これがタスクを達成する唯一の方法である場合があります。これらの API 関数は一般に C で記述されており、多くの場合、パラメーターとしてポインターが必要です。ただし、多くの場合、ポインターの使用を回避する方法で DllImport 宣言を記述することができます。たとえば、System.IntPtr クラスを使用します。
- パフォーマンス- 速度が最も重要な場合、ポインターは最適化されたパフォーマンスへのルートを提供できます。自分が何をしているのかを理解していれば、最も効率的な方法でデータにアクセスまたは操作することができます。ただし、多くの場合、ポインターに頼らずに必要なパフォーマンスの改善を行うことができるコードの他の領域があることに注意してください。コード プロファイラーを使用して、コード内のボトルネックを探してみてください。Visual Studio 2008 に付属しています。"
また、ポインターを使用する場合、コードを実行するにはより高いレベルの信頼が必要であり、ユーザーが許可しない場合、コードは実行されません。
最後に次の引用で締めくくります。
「ポインターを不必要に使用しないことを強くお勧めします。これは、書き込みとデバッグが難しくなるだけでなく、CLR によって課されるメモリ タイプ セーフ チェックにも失敗するからです。」
ガベージ コレクションは、存続期間の長いオブジェクトでは非効率的です。.Net のガベージ コレクターは、ほとんどのオブジェクトがかなり迅速に解放され、一部のオブジェクトが「永久に存続する」場合に最適に機能します。問題は、存続期間の長いオブジェクトがフル ガベージ コレクション中にのみ解放されることです。これにより、パフォーマンスが大幅に低下します。本質的に、寿命の長いオブジェクトはすぐに第 2 世代に移行します。
(詳細については、.Net の世代別ガベージ コレクターを参照してください: http://msdn.microsoft.com/en-us/library/ms973837.aspx )
オブジェクト、または一般的なメモリ使用が長期にわたる状況では、完全なガベージ コレクションを必要とせずにシステムにメモリを解放できるため、手動のメモリ管理によりパフォーマンスが向上します。
単一の大きなバイト配列、構造体、および多数のポインター演算に基づくある種のメモリ管理システムを実装すると、データが RAM に長期間保存される状況で、理論的にはパフォーマンスが向上する可能性があります。
残念ながら、.Net で長寿命になるオブジェクトのメモリを手動で管理する良い方法を知りません。これは基本的に、RAM に長期保存されたデータを持つアプリケーションが、すべてのメモリの完全なガベージ コレクションを実行すると、定期的に応答しなくなることを意味します。