none
Bilittableデータのピン止めは不必要でしょうか? RRS feed

  • 質問

  • いつもお世話になっております.恒です.
    環境:WindowsXPSP3
    開発言語VS2010Express C#
    .NetFramework4.0

    質問:
    アンマネージなDLLを使用する時に,
    Blittableなマネージデータを[In],[Out]属性で
    やりとりする時は,ピン止めが不必要
    という命題は正しいでしょうか?

    内容詳細:
    IntelのMKLのライブラリのExampleのFFTのソース
    を眺めていたのですが,
    <http://software.intel.com/en-us/articles/using-intel-mkl-in-your-c-program/>
    DLLに直接doubleのマネージの配列を渡しています.
    <MarshalAs(UnmanagedType.LPArray)>とかもGCHandleとかのピン止めも行っていません.

    <http://msdn.microsoft.com/ja-jp/library/75dwhxf7.aspx>
    を読んでみると,
    ○blittable型の一次元配列はBlittable。 (型の中に可変配列が含まれる場合は別)
    ○blittable 型の配列は、最適化のために、マーシャリング時にコピーされるのではなく固定されます
    と書いてあります.という事はピン止めは必要ないのかなと思いました.

    やってみた事:ピン止め有りと無しで100000回演算させて,エラーが起きない事を確認しました.

    以上

    2012年2月6日 13:14

回答

  • もともと、配列を渡した場合自動的に固定はされます。

    マネージの領域がそのまま渡されるかどうかという違いです。

    • 回答としてマーク 恒岡 2012年2月7日 12:06
    2012年2月6日 14:37
  • unmanaged に渡るメモリ領域は、すべて固定されていなければなりません。問題は明示的に固定を行う必要があるのか、マーシャリング時に固定されるのか、マーシャリング時に確保された固定されたメモリへ複製されるのか、といったところだけと思います。

    blittable は、メモリ領域に対して unmanaged と互換性があり、直接的に読み書きを実行できるかどうかです。メモリの固定とは直接的には関係ありません。このような特性を生かして、処理を自動化したり効率化しやすいというだけです。

    • 回答としてマーク 恒岡 2012年2月7日 12:06
    2012年2月7日 3:50
  • Marshal.Copy()はマネージドなメソッドです。マネージドである以上、通常の配列アクセスと同じくピン止めは不要です。
    • 回答としてマーク 恒岡 2012年2月7日 12:06
    2012年2月7日 11:48
  • 1. アンマネージメモリに固定も何もありません。

    2. Array.Copy を呼び出すときに固定を考えないのと同じです。

    • 回答としてマーク 恒岡 2012年2月7日 12:06
    2012年2月7日 11:51
  • 配列の 2 番目の要素から渡したいとか。

    明示的に固定する機会はそう多くはないでしょうね。

    C++/CLI なら pin_ptr はそれなりに使いではあるでしょうけど。

    • 回答としてマーク 恒岡 2012年2月8日 13:10
    2012年2月7日 23:48
  • 非同期IOとかもそうですが、アンマネージメソッドを呼び出し、その中でスレッドその他で別の処理が動きだし、メソッド呼び出しそのものはreturnしてしまう場合です。
    この場合、呼び出し側のマネージスレッドは次の処理に進むなどしてオブジェクトの生成・破棄が行われるとガベージコレクタが動き出す可能性があります。そうなるとアンマネージメソッドに渡したオブジェクトが移動されてしまう可能性が出てきます。

    …って話をすると、じゃあサーバーガベージコレクションや.NET 2.0 SP1(だっけ?)の同時実行ガベージコレクション、.NET 4のバックグラウンドガベージコレクションならアンマネージメソッドの実行中にもGCが動き出す可能性があって固定すべきじゃないかという話にもなりますが。同時実行は大丈夫かな…?

    それとは別の話で、ガベージ コレクションの基礎には

    大きなオブジェクト ヒープは圧縮されません。

    大きなオブジェクト ヒープには、85,000 バイトを超えるオブジェクトが格納されます。 大きなオブジェクト ヒープの中で特に大きなオブジェクトは、通常は配列になります。

    という記述もあり、この条件を満たす配列はそもそも固定不要です。
    # この仕様が今後変わらないという保証はありませんが。

    • 回答としてマーク 恒岡 2012年2月9日 14:16
    2012年2月9日 0:26

すべての返信

  • もともと、配列を渡した場合自動的に固定はされます。

    マネージの領域がそのまま渡されるかどうかという違いです。

    • 回答としてマーク 恒岡 2012年2月7日 12:06
    2012年2月6日 14:37
  • unmanaged に渡るメモリ領域は、すべて固定されていなければなりません。問題は明示的に固定を行う必要があるのか、マーシャリング時に固定されるのか、マーシャリング時に確保された固定されたメモリへ複製されるのか、といったところだけと思います。

    blittable は、メモリ領域に対して unmanaged と互換性があり、直接的に読み書きを実行できるかどうかです。メモリの固定とは直接的には関係ありません。このような特性を生かして、処理を自動化したり効率化しやすいというだけです。

    • 回答としてマーク 恒岡 2012年2月7日 12:06
    2012年2月7日 3:50
  • 恒です.

    お二方共お返事ありがとうございます.
    ○引数を配列にしたら,マーシャラが自動的にピン止めする
    ○Blittableとピン止めは関係ない
    と了解いたしました.後で回答マークつけさせていただきます.

    2点ほど少し違うケースでの確認なのですが,
    確認1.
    アンマネージDLL側でメモリ確保,解放を行い,そのDLL内部の
    配列データに対するメモリアドレスへのポインターIntPtrから

    マネージの配列データを受け取る時に,Marshal.Copyを

    使用していれば,ピン止めは必要ない.

    具体的なコード(すいません.C#のフォーラムなのにVBのコードで)

    Dim ImageBuffer As IntPtr
    Dim ImageLength As Integer
    アンマネージDLLのメソッドでbyrefでImageBuffer取得
    アンマネージDLLのメソッドでbyrefでImageLength取得
    ~
    Dim ExternalBuffer() As Byte
    ReDim ExternalBuffer(ImageLength - 1)
    Marshal.Copy(ImageBuffer, ExternalBuffer, 0, ImageLength) '<---ここピン止めいらない?

    確認2:
    Marshal.Copyを使用してバイト配列をIntPtrに与える場合,
    ピン止めは必要ない.

    具体的なコード
    バイト配列のデータから白黒ビットマップを作成する時のコードです.

    Using bmpLocalImage As Bitmap = New Bitmap(w, h, Imaging.PixelFormat.Format8bppIndexed)
       Dim bmpPalette As System.Drawing.Imaging.ColorPalette
       bmpPalette = bmpLocalImage.Palette
       For i = 0 To 255
          bmpPalette.Entries(i) = Color.FromArgb(i, i, i)
       Next
       bmpLocalImage.Palette = bmpPalette
       Dim bmpData As System.Drawing.Imaging.BitmapData = Nothing
      try    
           bmpData = bmpLocalImage.LockBits(New Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format8bppIndexed)
           Dim ptrScan0 As IntPtr = bmpData.Scan0
           Marshal.Copy(ExternalBuffer, 0, ptrScan0, w * h) '<---ここピン止めいらない?
        Finally
           If bmpData IsNot Nothing Then
              bmpLocalImage.UnlockBits(bmpData)
           End If
        End Try
        ~処理
        bmpLocalImage.Dispose()
     End Using

    一応,両方とも回数こなしてもエラーはおきないようです.ピン止めいらないのかと思います。
    2012年2月7日 11:21
  • Marshal.Copy()はマネージドなメソッドです。マネージドである以上、通常の配列アクセスと同じくピン止めは不要です。
    • 回答としてマーク 恒岡 2012年2月7日 12:06
    2012年2月7日 11:48
  • 1. アンマネージメモリに固定も何もありません。

    2. Array.Copy を呼び出すときに固定を考えないのと同じです。

    • 回答としてマーク 恒岡 2012年2月7日 12:06
    2012年2月7日 11:51
  • 皆様ありがとうございました。今回提示させて頂いたケースでは

    ピン止めいらないという事で理解いたしました。勉強になりました。

    ありがとうございました。回答マークをつけさせていただきました。

    ただそうすると最後に残った疑問は、ピン止めが要求されるのは

    具体的にどういう場合か?ですね。

    ピン止めが必要な場合というのは、アンマネージDLL側が

    マネージ側にアンマネージなメモリアドレスのポインタを要求する

    場合とかなんでしょうか?

    2012年2月7日 12:15
  • 配列の 2 番目の要素から渡したいとか。

    明示的に固定する機会はそう多くはないでしょうね。

    C++/CLI なら pin_ptr はそれなりに使いではあるでしょうけど。

    • 回答としてマーク 恒岡 2012年2月8日 13:10
    2012年2月7日 23:48
  • なるほど、そういう場合ですか。あとは非同期IOとかの場合ですかね。

    勉強になりました。ありがとうございました

    2012年2月8日 13:17
  • 非同期IOとかもそうですが、アンマネージメソッドを呼び出し、その中でスレッドその他で別の処理が動きだし、メソッド呼び出しそのものはreturnしてしまう場合です。
    この場合、呼び出し側のマネージスレッドは次の処理に進むなどしてオブジェクトの生成・破棄が行われるとガベージコレクタが動き出す可能性があります。そうなるとアンマネージメソッドに渡したオブジェクトが移動されてしまう可能性が出てきます。

    …って話をすると、じゃあサーバーガベージコレクションや.NET 2.0 SP1(だっけ?)の同時実行ガベージコレクション、.NET 4のバックグラウンドガベージコレクションならアンマネージメソッドの実行中にもGCが動き出す可能性があって固定すべきじゃないかという話にもなりますが。同時実行は大丈夫かな…?

    それとは別の話で、ガベージ コレクションの基礎には

    大きなオブジェクト ヒープは圧縮されません。

    大きなオブジェクト ヒープには、85,000 バイトを超えるオブジェクトが格納されます。 大きなオブジェクト ヒープの中で特に大きなオブジェクトは、通常は配列になります。

    という記述もあり、この条件を満たす配列はそもそも固定不要です。
    # この仕様が今後変わらないという保証はありませんが。

    • 回答としてマーク 恒岡 2012年2月9日 14:16
    2012年2月9日 0:26
  • >非同期IOとかもそうですが、アンマネージメソッドを呼び出し、その中でスレッドその他で別の処理が動きだし、メソッド呼び出しそのものはreturnしてしまう場合です。
    >この場合、呼び出し側のマネージスレッドは次の処理に進むなどしてオブジェクトの生成・破棄が行われるとガベージコレクタが動き出す可能性があります。そうなるとアンマネージメソッドに渡したオブジェクトが移動されてしまう可能性が出てきます。

    お返事ありがとうございます。なるほどです。

    >…って話をすると、じゃあサーバーガベージコレクションや.NET 2.0 SP1(だっけ?)の同時実行ガベージコレクション、.NET 4のバックグラウンドガベージコレクションならアンマネージメソッドの実行中にもGCが動き出す可能性があって固定すべきじゃないかという話にもなりますが。同時実行は大丈夫かな…?

    サーバGCは使ってないと思いますが、そのほかは怖いです。けど私の能力では検証不能です。アンマネージメソッドに渡されたマネージオブジェクトのメモリアドレスをアンマネージメソッドの実行中か終わった直後に取得できればいいのかな?

    >それとは別の話で、ガベージ コレクションの基礎には

    大きなオブジェクト ヒープは圧縮されません。

    大きなオブジェクト ヒープには、85,000 バイトを超えるオブジェクトが格納されます。 大きなオブジェクト ヒープの中で特に大きなオブジェクトは、通常は配列になります。

    >という記述もあり、この条件を満たす配列はそもそも固定不要です。
    ># この仕様が今後変わらないという保証はありませんが

    勉強になります。メモリコンパクションの対象にならないということは、高速化とメモリ断片化の危険とのトレー

    ドオフという事でしょうか。という事はもし85000バイト以上の配列データをある程度長く保持するなら、

    GenericListとかに移し替えておいた方がいいのでしょうか?

    2012年2月9日 14:34
  • ググると

    <http://msdn.microsoft.com/ja-jp/magazine/cc534993.aspx>

    を見つけました.

    ># この仕様が今後変わらないという保証はありませんが

    という事ですね.

    他の疑問は,大分元のスレからずれてきたので,再度勉強しなおして

    出直してきます.皆様方ありがとうございました.

    2012年2月11日 7:51