中年システムエンジニアのオモチャ箱

中年システムエンジニアが初体験のブログ活動。技術情報の備忘録以外も、色々と載せていければと思います。


VB.NET メモリリークによるメモリ解放の重要性(ジェネリックコレクション編)

以前、メモリリーク対策について MemoryStream、DataTable の解放方法を記載しました。

 

www.ma-se.com

www.ma-se.com

今回は、頻繁に使うであろうジェネリックコレクションの List クラスについてを記載します!

調査するための基本ロジック

下記は今回のメモリリーク調査で作成したロジックです。
約 1GB のメモリを消費しています。
List クラスということで、Add メソッドで追加してみました。

 

ソースコード

Private Sub TestListBase()

    Dim objList1 As New List(Of System.IO.MemoryStream)

    '========== 約 1GB のメモリを消費 ==========
    For i = 1 To 10
        '約 100MB のオブジェクトを生成
        Dim objMem As New System.IO.MemoryStream(100000000)
        '========== 何かしらの処理 ==========
        objList1.Add(objMem)
    Next
End Sub

メモリ解放を考慮していないロジック 

では、調査するための基本ロジックを踏まえて、下記はメモリ解放の対策をしていないロジックです。
BtnListTest1 を押下し、TestList1 メソッドを実行しても問題なく動作します。
BtnListTest1 を何度押下しても(=TestList1 メソッドを何度実行しても)問題ないはずです。

 

ソースコード

Private Sub BtnListTest1_Click(sender As Object, e As EventArgs) Handles BtnListTest1.Click
    Call Me.TestList1()
End Sub

 

Private Sub TestList1()
    Dim objList1 As New List(Of System.IO.MemoryStream)

    '========== 約 1GB のメモリを消費 ==========
    For i = 1 To 10
        '約 100MB のオブジェクトを生成
        Dim objMem As New System.IO.MemoryStream(100000000)
        '========== 何かしらの処理 ==========
        objList1.Add(objMem)
    Next
End Sub

メモリ解放処理をしていなくてもメモリリークが発生しない理由は、TestList1 メソッドの呼び出しが完了した段階で、.NET 側でメモリ解放処理(ガベージコレクションの発動)を暗黙的におこなっているからです。

 

では、下記のように BtnListTest1 を 2 回押下した動作と同じロジックを実行した場合は、どうなるでしょう?

 

ソースコード

Private Sub BtnListTest1_Click(sender As Object, e As EventArgs) Handles BtnListTest1.Click
    Call Me.TestList1()
End Sub

 

Private Sub TestList1()
    Dim objList1 As New List(Of System.IO.MemoryStream)
    Dim objList2 As New List(Of System.IO.MemoryStream)

 

    '========== 約 1GB のメモリを消費 ==========
    For i = 1 To 10
        '約 100MB のオブジェクトを生成
        Dim objMem As New System.IO.MemoryStream(100000000)
        '========== 何かしらの処理(その1) ==========
        objList1.Add(objMem)
    Next

 

    '========== 約 1GB のメモリを消費 ==========
    For i = 1 To 10
        '約 100MB のオブジェクトを生成
        Dim objMem As New System.IO.MemoryStream(100000000)
        '========== 何かしらの処理(その2) ==========
        objList2.Add(objMem)
    Next

End Sub

結果は、途中で Out Of Memoty のエラーで落ちますよね。
BtnListTest1 を 2 回押下した動作と同じ処理を行っているのに、何故、連続で同じロジックを実行するとエラーが発生するのでしょうか?
理由は、objList1 のメモリ解放処理を実施せずに、同一メソッド内で objList2 の生成でメモリ消費をしているためです。
BtnListTest1 を 2 回押下した場合は、TestList1 メソッドを 2 回呼び出していたので(暗黙的にメモリ解放を行っていたので)、問題なく動作しました。

これは悪い例なので、マネしないようにしてください。

 

 
メモリ解放を考慮したロジック

List クラスには、Dispose メソッドは存在しません。
では、Nothing をセットすればガベージコレクションの処理対象になるのかな?かな??

結論から言うと Nothing をセットするだけではダメです!!

 

VB.NET メモリリークによるメモリ解放の重要性(DataTable 編)でも、記載しましたが Clear メソッド実行後に Nothing をセットしましょう!

 

ソースコード

Private Sub BtnListTest1_Click(sender As Object, e As EventArgs) Handles BtnListTest1.Click
    Call Me.TestList1()
End Sub

 

Private Sub TestList1()
    Dim objList1 As New List(Of System.IO.MemoryStream)
    Dim objList2 As New List(Of System.IO.MemoryStream)

 

    '========== 約 1GB のメモリを消費 ==========
    For i = 1 To 10
        '約 100MB のオブジェクトを生成
        Dim objMem As New System.IO.MemoryStream(100000000)
        '========== 何かしらの処理(その1) ==========
        objList1.Add(objMem)
    Next
    objList1.Clear()
    objList1 = Nothing

 

    '========== 約 1GB のメモリを消費 ==========
    For i = 1 To 10
        '約 100MB のオブジェクトを生成
        Dim objMem As New System.IO.MemoryStream(100000000)
        '========== 何かしらの処理(その2) ==========
        objList2.Add(objMem)
    Next
    objList2.Clear()
    objList2 = Nothing

End Sub

 

このように、使用しなくなったオブジェクトをガベージコレクションの処理対象にするには、Nothing をセットするだけではなく、リソースの解放(Dispose、Clear、Close など)をした後にNothing をセットするように心がけましょうね。


Visual Basicの絵本 Windowsプログラミングわかる9つの扉

VB.NET キャストの速度比較

キャスト(型変換)って、方法は色々とありますが速度を気にしたことはありますか?
今回は文字列から数値に変換する場合に使用するキャストと、数値から文字列に変換する場合に使用するキャストの速度比較をおこないたいと思います。

文字列から数値に変換

下記 2 とおりのキャスト方法について速度比較をおこないます。

  1. Integer.Parse
  2. CInt

処理速度に明確な差を出すため、1,000 万回のループでキャストを実行しています。
また、変換文字列は「123」としていますが、深い意味はありません。

 

ソースコード

Private Sub CastStrToInt()

    Dim intTemp As Integer

 

    'Integer.Parse 変換

    Dim tc1 As Integer = System.Environment.TickCount

    For i As Integer = 1 To 10000000

        intTemp = Integer.Parse("123")

    Next

 

    '計測時間を算出してミリ秒で表示

    tc1 = System.Environment.TickCount - tc1

    Debug.Print("Integer.Parse で計測: {0}ミリ秒", tc1)

 

    'CInt 変換

    Dim tc2 As Integer = System.Environment.TickCount

    For i As Integer = 1 To 10000000

        intTemp = CInt("123")

    Next

 

    '計測時間を算出してミリ秒で表示

    tc2 = System.Environment.TickCount - tc2

    Debug.Print("CInt で計測: {0}ミリ秒", tc2)

Ennd Sub

 

実測結果は、

  • Integer.Parse で計測: 20757 ミリ秒
  • CInt で計測: 31405 ミリ秒

 でした。

 

CInt の方が Integer.Parse よりも、約 1.5 倍遅いことがわかりました。
文字列から数値に変換する場合は、Integer.Parse の方をおすすめします!

 

 
数値から文字列に変換

下記 2 とおりのキャスト方法について速度比較をおこないます。

  1. ToString
  2. CStr

処理速度に明確な差を出すため、1,000 万回のループでキャストを実行しています。
また、変換文字列は「123」としていますが、深い意味はありません。

 

ソースコード

Private Sub CastIntToStr()

    Dim strTemp As String

    Dim intVal As Integer = 123

 

    'ToString 変換

    Dim tc1 As Integer = System.Environment.TickCount

    For i As Integer = 1 To 10000000

        strTemp = intVal.ToString()

    Next

 

    '計測時間を算出してミリ秒で表示

    tc1 = System.Environment.TickCount - tc1

    Debug.Print("ToString で計測: {0}ミリ秒", tc1)

 

    'CStr 変換

    Dim tc2 As Integer = System.Environment.TickCount

    For i As Integer = 1 To 10000000

        strTemp = CStr(intVal)

    Next

 

    '計測時間を算出してミリ秒で表示

    tc2 = System.Environment.TickCount - tc2

    Debug.Print("CStr で計測: {0}ミリ秒", tc2)

End Sub

 

実測結果は、

  • ToString で計測: 1370 ミリ秒
  • CStr で計測: 1398 ミリ秒

でした。
ほぼ変わらないという結果となりました。
文字列から数値に変換する際に、Integer.Parse を使用するなら合わせるという意味で、ToString を使用した方がブログラムが綺麗に見える気がしますね。

キャストには、今回、計測した以外にも様々あります。
例えば、Convert や DirectCast 等々。
また、使用用途により何を使用するかは変わると思います。
例えば、Integer.Parse("123,456") ではエラーが発生しますが、CInt("123,456") ではエラーは発生しません。
ようは、変換する値にカンマが入っている場合、Integer.Parse ではエラーが発生しますが、CInt ではエラーは発生しません

 

使用用途にもよりますが、処理速度を気にしてプログラムを開発した方が良いかなと思います!


Visual Basicの絵本 Windowsプログラミングわかる9つの扉

VB.NET メモリリークによるメモリ解放の重要性(DataTable 編)

前回は下記で、MemoryStream オブジェクトについて記載しました。

www.ma-se.com


今回は、DataTable オブジェクトについてのお話です。
私の実務では、ほぼデータベースを使用するシステム開発なので、DataTable オブジェクトの方が馴染みがあるのです!

調査するための基本ロジック

下記は今回のメモリリーク調査で作成したロジックです。
約 1GB のメモリを消費していました。
尚、「COL_A」~「COL_C」までの 3 列追加、及び、800 万回のループでの行追加は、テストでメモリ消費をさせたいだけなので特に意味はありません。

 

ソースコード

Private Sub TestMemLeakBase()

    Dim objRow As DataRow

    Dim objDt As New DataTable()

    objDt.Columns.Add("COL_A")

    objDt.Columns.Add("COL_B")

    objDt.Columns.Add("COL_C")

    For i As Integer = 1 To 8000000

        objRow = objDt.NewRow()

        objRow.Item("COL_A") = "TEST1"

        objRow.Item("COL_B") = "TEST2"

        objRow.Item("COL_C") = "TEST3"

        objDt.Rows.Add(objRow)

    Next

End Sub

メモリ解放を考慮していないロジック 

では、調査するための基本ロジックを踏まえて、下記はメモリ解放の対策をしていないロジックです。
BtnDtTest1 を押下し、TestDt1 メソッドを実行しても問題なく動作します。
BtnDtTest1 を何度押下しても(=TestDt1 メソッドを何度実行しても)問題ないはずです。

 

ソースコード

Private Sub BtnDtTest1_Click(sender As Object, e As EventArgs) Handles BtnDtTest1.Click

    Call Me.TestDt1()

End Sub

 

Private Sub TestDt1()

    Dim objRow As DataRow

    Dim objDt1 As New DataTable()

    objDt1.Columns.Add("COL_A")

    objDt1.Columns.Add("COL_B")

    objDt1.Columns.Add("COL_C")

    For i As Integer = 1 To 8000000

        objRow = objDt1.NewRow()

        objRow.Item("COL_A") = "TEST1"

        objRow.Item("COL_B") = "TEST2"

        objRow.Item("COL_C") = "TEST3"

        objDt1.Rows.Add(objRow)

    Next

End Sub

メモリ解放処理をしていなくてもメモリリークが発生しない理由は、TestDt1 メソッドの呼び出しが完了した段階で、.NET 側でメモリ解放処理(ガベージコレクションの発動)を暗黙的におこなっているからです。 

 

では、下記のように BtnDtTest1 を 2 回押下した動作と同じロジックを実行した場合は、どうなるでしょう?

 

ソースコード

Private Sub BtnDtTest1_Click(sender As Object, e As EventArgs) Handles BtnDtTest1.Click

    Call Me.TestDt1()

End Sub

 

Private Sub TestDt1()

    Dim objRow As DataRow

 

    '1 回目の呼び出し

    Dim objDt1 As New DataTable()

    objDt1.Columns.Add("COL_A")

    objDt1.Columns.Add("COL_B")

    objDt1.Columns.Add("COL_C")

    For i As Integer = 1 To 8000000

        objRow = objDt1.NewRow()

        objRow.Item("COL_A") = "TEST1"

        objRow.Item("COL_B") = "TEST2"

        objRow.Item("COL_C") = "TEST3"

        objDt1.Rows.Add(objRow)

    Next

 

    '2 回目の呼び出し

    Dim objDt2 As New DataTable()

    objDt2.Columns.Add("COL_A")

    objDt2.Columns.Add("COL_B")

    objDt2.Columns.Add("COL_C")

    For i As Integer = 1 To 8000000

        objRow = objDt2.NewRow()

        objRow.Item("COL_A") = "TEST1"

        objRow.Item("COL_B") = "TEST2"

        objRow.Item("COL_C") = "TEST3"

        objDt2.Rows.Add(objRow)

    Next

End Sub

結果は、途中で Out Of Memoty のエラーで落ちますよね。
BtnDtTest1 を 2 回押下した動作と同じ処理を行っているのに、何故、連続で同じロジックを実行するとエラーが発生するのでしょうか?
理由は、obj1Dt1 のメモリ解放処理を実施せずに、同一メソッド内で objDt2 の生成でメモリ消費をしているためです。
BtnDtTest1 を 2 回押下した場合は、TestDt1 メソッドを 2 回呼び出していたので(暗黙的にメモリ解放を行っていたので)、問題なく動作しました。

これは悪い例なので、マネしないようにしてください。

 

 
メモリ解放を考慮したロジック

では、メモリリークが発生したロジックに、メモリ解放処理を入れてみましょう!

  1. 使用済みになった後に、Nothing をセットする。
    または、Dispose メソッドが呼び出せる場合は、Dispose メソッド呼び出し後、Nothing をセットする。
    ネットで調べると、大体上記の事が出てくると思います。

    ソースコード

    Private Sub BtnDtTest1_Click(sender As Object, e As EventArgs) Handles BtnDtTest1.Click

        Call Me.TestMem1()

    End Sub

     

    Private Sub TestDt1()

        Dim objRow As DataRow

     

        '1 回目の呼び出し

        Dim objDt1 As New DataTable()

        objDt1.Columns.Add("COL_A")

        objDt1.Columns.Add("COL_B")

        objDt1.Columns.Add("COL_C")

        For i As Integer = 1 To 8000000

            objRow = objDt1.NewRow()

            objRow.Item("COL_A") = "TEST1"

            objRow.Item("COL_B") = "TEST2"

            objRow.Item("COL_C") = "TEST3"

            objDt1.Rows.Add(objRow)

        Next

        objDt1.Dispose()

        objDt1 = Nothing

     

        '2 回目の呼び出し

        Dim objDt2 As New DataTable()

        objDt2.Columns.Add("COL_A")

        objDt2.Columns.Add("COL_B")

        objDt2.Columns.Add("COL_C")

        For i As Integer = 1 To 8000000

            objRow = objDt2.NewRow()

            objRow.Item("COL_A") = "TEST1"

            objRow.Item("COL_B") = "TEST2"

            objRow.Item("COL_C") = "TEST3"

            objDt2.Rows.Add(objRow)

        Next

        objDt2.Dispose()

        objDt2 = Nothing

    End Sub

    VB.NET メモリリークによるメモリ解放の重要性(MemoryStream 編)に引き続き、また予期せぬ Out Of Memoty のエラーが発生しました。
    色々と調べてみると、DataTable オブジェクトでは Clear メソッドで、リソースが解放されるみたいです。
    では、Dispose メソッドを、Clear メソッドに変更してみましょう!

    ソースコード

    Private Sub BtnDtTest1_Click(sender As Object, e As EventArgs) Handles BtnDtTest1.Click

        Call Me.TestMem1()

    End Sub

     

    Private Sub TestDt1()

        Dim objRow As DataRow

     

        '1 回目の呼び出し

        Dim objDt1 As New DataTable()

        objDt1.Columns.Add("COL_A")

        objDt1.Columns.Add("COL_B")

        objDt1.Columns.Add("COL_C")

        For i As Integer = 1 To 8000000

            objRow = objDt1.NewRow()

            objRow.Item("COL_A") = "TEST1"

            objRow.Item("COL_B") = "TEST2"

            objRow.Item("COL_C") = "TEST3"

            objDt1.Rows.Add(objRow)

        Next

        objDt1.Dispose()  objDt1.Clear()

        objDt1 = Nothing

     

        '2 回目の呼び出し

        Dim objDt2 As New DataTable()

        objDt2.Columns.Add("COL_A")

        objDt2.Columns.Add("COL_B")

        objDt2.Columns.Add("COL_C")

        For i As Integer = 1 To 8000000

            objRow = objDt2.NewRow()

            objRow.Item("COL_A") = "TEST1"

            objRow.Item("COL_B") = "TEST2"

            objRow.Item("COL_C") = "TEST3"

            objDt2.Rows.Add(objRow)

        Next

        objDt2.Dispose()  objDt2.Clear()

        objDt2 = Nothing

    End Sub

     これで、メモリリークが発生せずに実行できましたね!

  2. Using を使用する。
    ネットで調べると、Using を使用することにより、リソースが解放されるとの事が出てくると思います。

    VB.NET メモリリークによるメモリ解放の重要性(MemoryStream 編)では、Using を使用することはできませんでした。

    DataTable オブジェクトではどうでしょうか?

    ソースコード

    Private Sub BtnDtTest2_Click(sender As Object, e As EventArgs) Handles BtnDtTest2.Click

        Call Me.TestDt2()

    End Sub

     

    Private Sub TestDt2()

        Dim objRow As DataRow

     

        '1 回目の呼び出し

        Using objDt1 As New DataTable()

            objDt1.Columns.Add("COL_A")

            objDt1.Columns.Add("COL_B")

            objDt1.Columns.Add("COL_C")

            For i As Integer = 1 To 8000000

                objRow = objDt1.NewRow()

                objRow.Item("COL_A") = "TEST1"

                objRow.Item("COL_B") = "TEST2"

                objRow.Item("COL_C") = "TEST3"

                objDt1.Rows.Add(objRow)

            Next

        End Using

     

        '2 回目の呼び出し

        Using objDt2 As New DataTable()

            objDt2.Columns.Add("COL_A")

            objDt2.Columns.Add("COL_B")

            objDt2.Columns.Add("COL_C")

            For i As Integer = 1 To 8000000

                objRow = objDt2.NewRow()

                objRow.Item("COL_A") = "TEST1"

                objRow.Item("COL_B") = "TEST2"

                objRow.Item("COL_C") = "TEST3"

                objDt2.Rows.Add(objRow)

            Next

        End Using

    End Sub

    結果は、VB.NET メモリリークによるメモリ解放の重要性(MemoryStream 編)と同様に、途中で Out Of Memoty のエラーで落ちちゃいました…。
    VB.NET メモリリークによるメモリ解放の重要性(MemoryStream 編)の時と同様に、Using は使用できないのかな??
    と思ったのですが、Using で終了する前に、DataTable オブジェクトの Clear メソッドを呼び出すことによりメモリ解放することができました!

    ソースコード

    Private Sub BtnDtTest2_Click(sender As Object, e As EventArgs) Handles BtnDtTest2.Click

        Call Me.TestDt2()

    End Sub

     

    Private Sub TestDt2()

        Dim objRow As DataRow

     

        '1 回目の呼び出し

        Using objDt1 As New DataTable()

            objDt1.Columns.Add("COL_A")

            objDt1.Columns.Add("COL_B")

            objDt1.Columns.Add("COL_C")

            For i As Integer = 1 To 8000000

                objRow = objDt1.NewRow()

                objRow.Item("COL_A") = "TEST1"

                objRow.Item("COL_B") = "TEST2"

                objRow.Item("COL_C") = "TEST3"

                objDt1.Rows.Add(objRow)

            Next

            objDt1.Clear()

        End Using

     

        '2 回目の呼び出し

        Using objDt2 As New DataTable()

            objDt2.Columns.Add("COL_A")

            objDt2.Columns.Add("COL_B")

            objDt2.Columns.Add("COL_C")

            For i As Integer = 1 To 8000000

                objRow = objDt2.NewRow()

                objRow.Item("COL_A") = "TEST1"

                objRow.Item("COL_B") = "TEST2"

                objRow.Item("COL_C") = "TEST3"

                objDt2.Rows.Add(objRow)

            Next

            objDt2.Clear()

        End Using

    End Sub

     

VB.NET メモリリークによるメモリ解放の重要性(MemoryStream 編)とは、若干、結果が異なりましたね。
Using を使用しても、完全にリソースが解放されない事には疑問が残りますが…。

 

オブジェクトにより、リソースの解放方法(Dispose、Clear、Close など)は異なりました。
しかしリソースを解放し、ガベージコレクションの処理対象(Using を使用や、Nothing のセット)にすれば、メモリリーク対策になるという事を忘れずに!


Visual Basicの絵本 Windowsプログラミングわかる9つの扉

VB.NET メモリリークによるメモリ解放の重要性(MemoryStream 編)

みなさんアプリケーションを開発している際、メモリリークって気にしてますか?
私は、小規模のクラサバ、且つ、非常駐アプリの場合は、正直それほど気にしていません。
しかし、24 時間稼働するアプリケーションだと話は別です。

調査するための基本ロジック

下記は今回のメモリリーク調査で作成したロジックです。
約 1GB のメモリを消費しています。

 

ソースコード

Private Sub TestMemBase()
    Dim objMem1 As New System.IO.MemoryStream(1000000000)
    '========== 何かしらの処理 ==========
End Sub

メモリ解放を考慮していないロジック

では、調査するための基本ロジックを踏まえて、下記はメモリ解放の対策をしていないロジックです。
BtnMemTest1 を押下し、TestMem1 メソッドを実行しても問題なく動作します。
BtnMemTest1 を何度押下しても(=TestMem1 メソッドを何度実行しても)問題ないはずです。

 

ソースコード

Private Sub BtnMemTest1_Click(sender As Object, e As EventArgs) Handles BtnMemTest1.Click

    Call Me.TestMem1()

End Sub

 

Private Sub TestMem1()

    Dim objMem1 As New System.IO.MemoryStream(1000000000)

    '========== 何かしらの処理 ==========

End Sub

 メモリ解放処理をしていなくてもメモリリークが発生しない理由は、TestMem1 メソッドの呼び出しが完了した段階で、.NET 側でメモリ解放処理(ガベージコレクションの発動)を暗黙的におこなっているからです。

 

では、下記のように BtnMemTest1 を 2 回押下した動作と同じロジックを実行した場合は、どうなるでしょう?

 

ソースコード

Private Sub BtnMemTest1_Click(sender As Object, e As EventArgs) Handles BtnMemTest1.Click

    Call Me.TestMem1()

End Sub

 

Private Sub TestMem1()

    Dim objMem1 As New System.IO.MemoryStream(1000000000)

    '========== 何かしらの処理(その1) ==========

 

    Dim objMem2 As New System.IO.MemoryStream(1000000000)

    '========== 何かしらの処理(その2) ==========

End Sub

結果は、途中で Out Of Memoty のエラーで落ちますよね。
BtnMemTest1 を 2 回押下した動作と同じ処理を行っているのに、何故、連続で同じロジックを実行するとエラーが発生するのでしょうか?
理由は、objMem1 のメモリ解放処理を実施せずに、同一メソッド内で objMem2 の生成でメモリ消費をしているためです。
BtnMemTest1 を 2 回押下した場合は、TestMem1 メソッドを 2 回呼び出していたので(暗黙的にメモリ解放を行っていたので)、問題なく動作しました。

これは悪い例なので、マネしないようにしてください。

 

 
メモリ解放を考慮したロジック

では、メモリリークが発生したロジックに、メモリ解放処理を入れてみましょう!

  1. 使用済みになった後に、Nothing をセットする。
    または、Dispose メソッドが呼び出せる場合は、Dispose メソッド呼び出し後、Nothing をセットする。
    ネットで調べると、大体上記の事が出てくると思います。

    ソースコード

    Private Sub BtnMemTest1_Click(sender As Object, e As EventArgs) Handles BtnMemTest1.Click

        Call Me.TestMem1()

    End Sub

     

    Private Sub TestMem1()

        Dim objMem1 As New System.IO.MemoryStream(1000000000)

        '========== 何かしらの処理(その1) ==========

        objMem1.Dispose()

        objMem1 = Nothing

     

        Dim objMem2 As New System.IO.MemoryStream(1000000000)

        '========== 何かしらの処理(その2) ==========

        objMem2.Dispose()

        objMem2 = Nothing

    End Sub

    下記の理由により、objMem2 のメモリ消費時に、objMem1 のメモリを解放しているから問題なく動作します。
    Dispose メソッド : リソースを解放します
    Nothing のセット : ガベージコレクションの処理対象とするためのセット

  2. Using を使用する。
    ネットで調べると、Using を使用することにより、リソースが解放されるとの事が出てくると思います。
    いざ、実装です!

    ソースコード

    Private Sub BtnMemTest2_Click(sender As Object, e As EventArgs) Handles BtnMemTest2.Click

        Call Me.TestMem2()

    End Sub

     

    Private Sub TestMem2()

        Using objMem1 As New System.IO.MemoryStream(1000000000)

            '========== 何かしらの処理(その1) ==========

        End Using

     

        Using objMem2 As New System.IO.MemoryStream(1000000000)

            '========== 何かしらの処理(その2) ==========

        End Using

    End Sub

    結果は…、途中で Out Of Memoty のエラーで落ちちゃいました!!
    ??です
    Using で Dispose されて、ガベージコレクションの処理対象となるのでは??
    う~ん…。
    色々と調べてみると、Using で作成した MemoryStream は、内部バッファに値が保持されてしまうらしいです。
    同一メソッド内で上記のように実装する場合は、Using は使用せずに、New で作成して、明示的に Dispose メソッド呼び出し後 Nothing をセットして使うべきなのかな??

いまいち納得できない部分もありますが、メモリリークを起こさないためには、

  • 明示的に解放する(Dispose 等のリソースの解放後、Nothing をセット
  • Using を使用する

を心がけたほうが良いかと思います。

 

VB.NET メモリリークって気にしてますか?(DataTable 編)もあわせて読んでみてもらえればと思います。


Visual Basicの絵本 Windowsプログラミングわかる9つの扉

Visual Studio 2017 で iPhone スマホアプリを動かしてみる【総集編】

何回かに分けて、Visual Studio 2017 のインストールから、iPhone の実機動作までの手順を紹介してきました。

 


あいだに他の記事も挟んでいたので、総集編ということでまとめてみました。
ブックマークを付けておいてもらえると便利かもしれません。

 

  1. Visual Studio でスマホアプリ開発はできるのか?

  2. Xamarin + Visual Studio 2017 をインストールしよう
    関連記事として Visual Studio 2017 のオフラインインストール方法も載せました。

  3. Xamarin Live Player をインストールしてみよう

  4. Visual Studio 2017 で iPhone スマホアプリを動かしてみる

Beginning Visual Studio for MacBuild Cross-Platform Apps with Xamarin and .NET Core【電子書籍】[ Alessandro Del Sole ]

価格:3,993円
(2018/9/23 18:37時点)
感想(0件)

Visual Studio 2017 で iPhone スマホアプリを動かしてみる

前回までで、パソコンの開発環境構築(Visual Studio 2017)と、iPhone 実機の環境構築(Xamarin Live Player)が整いました。
環境構築がまだの方は、下記の記事を参考にしてください。

  1. Xamarin + Visual Studio 2017 をインストールしよう
  2. Xamarin Live Player をインストールしてみよう

今回は、Xamarin のホームページに公開されている、サンプルプログラムをダウンロードし、Visual Studio 2017 と Xamarin Live Player を連携して、スマホアプリ(今回は iPhone 限定です)を動かしてみましょう!

 

 
サンプルプログラムをダウンロードしよう
  1. Xamarin のホームページ Developer Centerhttps://developer.xamarin.com/)を開きます。
    そして、[Samples]を押下します。

    f:id:middle-aged-se:20180327180453j:plain

  2. 検索欄に「color」と入力すると、下に候補が表示されます。
    その中の「Color Control Sample(iOS)」を押下します。

    f:id:middle-aged-se:20180327180449j:plain

  3. Color Control Sample(iOS)ページが表示されるので、[Download]を押下します。

    f:id:middle-aged-se:20180327180445j:plain

  4. 下記ファイルがダウンロードされました。

    f:id:middle-aged-se:20180327180442j:plain

  5. 解凍するフォルダを決めて、解凍してください。
    ここで注意点があります。
    解凍するフォルダには、日本語文字は含めずに英数字としてください!
    日本語文字のフォルダ名を使用すると、正常に動作しない場合があるそうです。
    私は「C:\Develop」フォルダを作成して解凍しました。

    f:id:middle-aged-se:20180327180440j:plain

Visual Studio 2017 でサンプルプログラムを開こう
  1. 解凍したファイルから、「ColorControl.sln」を選択し、ダブルクリックします。

    f:id:middle-aged-se:20180327180550j:plain

  2. Visual Studio 2017 をインストール後、初めて「sln(ソリューション)ファイル」をダブルクリックすると、下記メッセージが表示されると思います。
    表示された場合は、下記を確認後、[OK]ボタンを押下してください。
    Microsoft Visual Studio Version Selector]選択されていること
    (初期で選択されています)
    [常にこのアプリケーションを使って .sln ファイルを開く]チェックボックスチェックをONにする
    (初期ではチェックOFFです)

    f:id:middle-aged-se:20180327180546j:plain

  3. 上記手順で Visual Studio 2017 に、開発で必要な各種ファイルが読み込まれます。
    下記の警告ダイアログが表示された場合は、[ソリューションの再読み込み]ボタンを押下してください。

    f:id:middle-aged-se:20180327180540j:plain

 

これで、実行するサンプルプログラムの準備が整いました。
では、実機の iPhone にサンプルプログラムを転送して、動かしてみましょう!

Visual Studio 2017 でサンプルプログラムを動かそう

サンプルプログラムを動かす前の注意点です。
必ず、Visual Studio 2017 がインストールされているパソコンと、実機の iPhone は、同じネットワークとしてください。

  • <OK な例>
    パソコンが自宅の Wi-Fi に接続され、iPhone も自宅の Wi-Fi に接続されている。
  • <NG な例>
    パソコンが自宅の Wi-Fi に接続されているが、iPhone は電話回線で接続されている。

 

  1. 下記のとおり、赤枠で囲まれている設定がされているか確認します。
    [Live Player]左に表示されている緑三角ボタンを押下します。

    f:id:middle-aged-se:20180327180537j:plain

  2. 下記のような画面が表示されます。
    左側の QR コードは、iPhone にインストールした、Xamarin Live Player で使用します。
    右側の情報は、接続する iPhone のデバイス名が表示されます。
     ※デバイス名の確認は iPhone「設定>一般>情報>名前」で確認できます。

    f:id:middle-aged-se:20180327180532j:plain

  3. iPhone の Xamarin Live Player を起動します。
    起動後、[Pair to Visual Studioを押下します。

    f:id:middle-aged-se:20180327180648j:plain

  4. 下記が表示されたら、[許可]を押下します。

    f:id:middle-aged-se:20180327180646j:plain

  5. カメラが起動しますので、パソコンに表示されている QR コードを読み取ってください。
    一番下の赤枠は次回以降、パソコンと iPhone の連携で使用する英数字 6 桁のコードが表示されています。
    一度、パソコンと iPhone を連携してしまえば、次回以降は QR コードを読み取らなくても良いそうです。

    f:id:middle-aged-se:20180327180643j:plain

  6. 下記インフォメーションダイアログが表示された場合、[OK]ボタンを押下します。

    f:id:middle-aged-se:20180327180640j:plain

  7. QR コードの読み取り後、Visual Studio 2017 が iPhone にサンプルプログラムを転送し、アプリケーションが起動します。
    私の環境ではエラーダイアログが 2 回表示されましたが、エラーダイアログの[OK]ボタンを押下したら次に進めました。
    ただし、デバッグはできないようでしたが…。

    f:id:middle-aged-se:20180327180638j:plain

  8. サンプルプログラムでは、[Take Phote]ボタンの押下で、写真を撮り、撮った写真は下のエリアに表示されます。
    そして、[Contrast]、[Saturation]、[Brightness]の3 つのスライドバーで、撮った写真の色調整を行うことができます。

    f:id:middle-aged-se:20180327180742j:plain

  9. では、ちょっとだけプログラムを変更してみましょう!
    ちゃんと、iPhone のアプリケーションに反映されるかな??
    右上に表示されている、「ソリューションエクスプローラー」から、「ImageViewController.cs」ファイルをダブルクリックすると、編集用ウィンドウが表示されます。
    そしたら、下記のとおり変更します。
    30 行目
      変更前 : Title = "Color Controls Pro";
      変更後 : Title = "色の調整";
    37 行目
      変更前 : cameraButton.SetTitle ("Take Photo", UIControlState.Normal);
      変更後 : cameraButton.SetTitle ("写真を撮る", UIControlState.Normal);
    59 行目
      変更前 : resetButton.SetTitle ("Reset", UIControlState.Normal);
      変更後 : resetButton.SetTitle ("リセット", UIControlState.Normal);

    f:id:middle-aged-se:20180327180738j:plain

  10. 再び、Visual Studio 2017 の、[Live Player]左に表示されている緑三角ボタンを押下します。
    今度は、QR コードを読み取らずに、Xamarin Live Player に表示されたコードで動かしてみましょう!

    f:id:middle-aged-se:20180327180735j:plain

  11. iPhone の Xamarin Live Player を起動します。
    起動後、[Pair to Visual Studioを押下します。

    f:id:middle-aged-se:20180327180733j:plain

  12. 一番下の赤枠に「ABC123」のように英数字 6 桁が表示されていると思います。
    Xamarin Live Player のコードを、Visual Studio 2017 のコード入力テキストボックスに入力し、[接続]ボタンを押下します。

    f:id:middle-aged-se:20180327180730j:plain

    f:id:middle-aged-se:20180327180735j:plain

  13. 英語で表示されていた文字列が、変更した日本語文字で表示されましたね!
    変更した内容が、実機の iPhone のアプリケーションに反映できました!

    f:id:middle-aged-se:20180327180803j:plain

 

どうでしたか?
Visual Studio 2017 を使用して、手軽に iPhone で動かすことができましたね!
今回はサンプルプログラムを使用しましたが、実際には自分で一から作成して iPhone で動かせたら、もっと感動ものですよね。
ゆくゆくは、クロスプラットフォームでの開発を味わってみたいものです。
その前に、実行時に発生するエラーの対応を解決しないとかな。

 

Visual Studio は多くの開発者で使われている開発ツールです。(私も Visual Studio で開発している一人です)
もっと参考資料が出回れば、Visual Studio で、iPhoneAndroidWindows Phone の開発が進み、効率化できるのではないかと期待しています!

Beginning Visual Studio for MacBuild Cross-Platform Apps with Xamarin and .NET Core【電子書籍】[ Alessandro Del Sole ]

価格:3,993円
(2018/9/23 18:37時点)
感想(0件)

Visual Studio 2017 のオフラインインストール方法

Xamarin + Visual Studio 2017 をインストールしようでは、オンラインインストールをしました。

 

しかし、個人で使用する際や、教育機関の学習で使用する等(Community エディションの場合の話ですが)、複数インストールしたい場合にオンラインインストールを実行すると、インストールファイルを何度もダウンロードしてしまいます。


以前のバージョンでは、ISOファイルでインストールファイルをダウンロードもできたのですが、Visual Studio 2017 では、ISOファイルはないようです。

オンラインインストールだと時間がかかるのだけど、どうにかならないの?

どうにかなります!
ちゃんと、オフラインでインストールできるようになるのです!

 

 
オフラインインストールファイルの作成方法
  1. Visual Studio でスマホアプリ開発はできるのか?でダウンロードした下記ファイルを準備します。
    (これ以降の手順では、C ドライブの、temp フォルダC:\temp)に、ファイルが存在するものとします)

    f:id:middle-aged-se:20180327131138j:plain

  2. Windows キーを押しながら、R キーを押します。
    または、[スタート] メニューから [ファイル名を指定して実行]をクリック
  3. 下記のとおり、[名前]「cmd」と入力し、[OK]ボタンを押下します。

    f:id:middle-aged-se:20180327131135j:plain

  4. 下記のとおり、DOS プロンプトが表示された後、「vs_community__353419847.1519277426.exe --layout c:\temp\vs2017offline」と入力します。
    ダウンロードするフォルダを「c:\temp\vs2017offline」と指定していますが、このフォルダ名を変更すれば、任意のフォルダにダウンロードすることが可能です。

    f:id:middle-aged-se:20180327131133j:plain

  5. しばらくすると、下記の画面が表示されます。

    f:id:middle-aged-se:20180327131130j:plain

  6. またしばらくすると、新しい DOS プロンプトが表示され、インストールファイルのダウンロードが開始されます。
    「Layout progress: 0.00%」の表示が、ダウンロードの進捗率になります。
    これが 100% になれば完了ですが、かなりの時間がかかりますので、夜、寝る前に実行して放置した方が良さそうですね。

    f:id:middle-aged-se:20180327131127j:plain

  7. ダウンロードが完了すると、下記の表示で停止しますので、何でも良いのでキーボードのキーを押下してください。
    すると、DOS プロンプトが閉じます。

    f:id:middle-aged-se:20180327131153j:plain

  8.  ダウンロードフォルダ(今回の場合だと「c:\temp\vs2017offline」フォルダ)に、「vs_setup.exe」ファイルが作成されています。

    f:id:middle-aged-se:20180327131151j:plain

    こちらを、ダブルクリックするとインストールが開始されます。
    インストール方法の詳細は、Xamarin + Visual Studio 2017 をインストールしようを参照してください。


Visual Basicの絵本 Windowsプログラミングわかる9つの扉