概要
- C# は多用途な言語であり、低レベルから高レベルまで幅広い開発が可能
- 配列アクセスの境界チェック がパフォーマンスに影響を与える場合がある
- unsafeコード やポインタ演算で高速化できるが、安全性に課題
- SpanやReadOnlySpan の導入で、安全かつ高速なゼロコピー操作が実現
- .NETランタイム でもSpanを活用した新しいAPIが増加
C#の多様性と低レベル最適化
- C# は モバイルアプリ、 デスクトップアプリ、 ゲーム、 Webサイト、 サービス/API の開発に対応
- Java風 の抽象化豊富な設計も可能だが、 unsafeコード や ポインタ による低レベル制御もサポート
- パフォーマンス向上 や Cライブラリとの連携 には GCを介さない生ポインタ 利用が有効
配列アクセスと境界チェック
- C#の配列アクセス は安全性のため 境界チェック が自動で行われる
- forループ でインデックスが明確な場合、 コンパイラが境界チェックを省略 できる最適化
- 動的なインデックス や外部から渡された範囲の場合、 境界チェックが残りパフォーマンス低下
unsafeコードのメリット・デメリット
- unsafe関数 や ポインタ演算 で境界チェックを完全排除し、 高速なコード生成 が可能
- 不正なlength値 で例外ではなく クラッシュや誤動作、 バッファオーバーフロー脆弱性 のリスク
- unsafe関数の呼び出し元もunsafe指定 が必要で、安全性確保が困難
Spanによる安全かつ高速な配列操作
- 配列の部分範囲と実体の整合性 を保つために Span型 を導入
- readonly struct Span
- T*ポインタ と 長さ情報 を保持するイミュータブル型
- readonly struct Span
- Span は ref struct として宣言され、 スタック上のみ存続 しヒープに逃げない
- ガーベジコレクション による解放リスクを排除
- 他のref struct 内でのみ保持可能、 ボックス化不可
- Span を使った関数は 境界チェック不要 で高速化、部分配列も安全に受け渡し可能
ReadOnlySpanの利点
- ReadOnlySpan で受け取れば 不変保証、内容の変更をコンパイラが防止
- readonly配列 では参照自体しか守れないが、 ReadOnlySpan は内容自体も保護
ゼロコピーAPIと実用例
Quicksortの比較
- 従来のQuicksort は 配列と範囲インデックス で部分配列を表現し、 境界チェックやオーバーフロー のリスク
- Spanを使うと、 範囲演算子(..) で部分配列を安全かつ直感的に表現
- (low + high) / 2 のようなオーバーフローも発生しにくい
- 境界チェック不要 でunsafe並みのパフォーマンス
- コードの可読性・表現力向上
.NETランタイムのゼロコピーAPI
- .NET では Span や ReadOnlySpan 対応のAPIが増加
- String.Split のようなAPIでも 新たなバッファ生成を避けて メモリ効率向上
- 例: ReadOnlySpan でCSV行を分割・処理することでGC負荷減少
まとめ
- C# は 高レベル抽象化 から 低レベル最適化 まで柔軟に対応
- unsafeコード はパフォーマンスに優れるが、安全性に難
- Span や ReadOnlySpan の導入で、安全かつ高速な ゼロコピー操作 が容易に
- .NETランタイム もSpanベースのAPIを拡充し、現代的なパフォーマンスと安全性を両立