C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

No.81781 の関連記事表示

<< 0 | 1 >>
■81781  DataSetの破棄について
□投稿者/ sk -(2016/11/14(Mon) 11:38:37)

    分類:[.NET 全般] 

    OS:windows server 2012
    環境:visual studio 2012 (VB)

    以下のような処理を延々とタイマー内で実行すると
    5000万回を超えたぐらいで、new実行時に応答が無くなってしまいます。
    単純にDataSetのNewを繰り返すと発生してしまうものなのでしょうか?
    また、下記処理に何か問題があるのでしょうか?
    ご教示願います。


    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

    Dim dstData As DataSet
    dstData = New DataSet1
    dstData.Clear()
    'dstData.Disposeでも結果は同じだった。

    End Sub
親記事 /過去ログ140より / 関連記事表示
削除チェック/

■81788  Re[1]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/14(Mon) 17:51:34)
    No81781 (sk さん) に返信
    > 5000万回を超えたぐらいで、new実行時に応答が無くなってしまいます。

    5000万回というと、1秒更新で1.6年間、
    50ミリ秒更新で一ヶ月弱という回数ですね。

    追検証しにくい物だとは思いますが、応答が無くなる回数は
    いつも 5000万回 を超えたあたりなのでしょうか。


    とりあえずタイマーなしで、空の DataSet1 を生成してみましたが、
    特に問題は発生しませんでした。カウントアップの追跡部分など、
    何か別の場所で問題が起きている可能性は無いでしょうか。

     For I = 1 To 70000000
      Dim dstData As DataSet
      dstData = New DataSet1()
      dstData.Clear()
     Next
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81789  Re[2]: DataSetの破棄について
□投稿者/ sk -(2016/11/14(Mon) 19:13:42)
    No81788 (魔界の仮面弁士 さん) に返信
    > ■No81781 (sk さん) に返信
    >>5000万回を超えたぐらいで、new実行時に応答が無くなってしまいます。
    >
    > 5000万回というと、1秒更新で1.6年間、
    > 50ミリ秒更新で一ヶ月弱という回数ですね。
    >
    > 追検証しにくい物だとは思いますが、応答が無くなる回数は
    > いつも 5000万回 を超えたあたりなのでしょうか。
    >
    >
    > とりあえずタイマーなしで、空の DataSet1 を生成してみましたが、
    > 特に問題は発生しませんでした。カウントアップの追跡部分など、
    > 何か別の場所で問題が起きている可能性は無いでしょうか。
    >
    >  For I = 1 To 70000000
    >   Dim dstData As DataSet
    >   dstData = New DataSet1()
    >   dstData.Clear()
    >  Next

    返信ありがとうございます。
    カウントアップ処理も確認しましたが、問題ないと考えています。
    また、こちらの環境でも空のDataSetでは現象は発生しませんでした。
    ただし、データセットにデータベース(postgres)をロード(テーブル80個)した
    状態では5000万回程度で100%発生します。
    毎回同じぐらいの回数で発生するので、何か解放漏れがあるのではないか?
    と推測しています。
    (メモリやハンドル、スレッドの上昇は見られません‥)
    Clearではリソースが完全に解放されないということがあるのでしょうか?

記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81798  Re[3]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/15(Tue) 10:02:27)
    No81789 (sk さん) に返信
    > ただし、データセットに
    型付きDataSet を用いず、素の System.Data.DataSet に Tables.Add していった場合も
    同様の現象になるのでしょうか。

    また、その型付き DataSetは Webサービス等で公開されたものだったりはしないでしょうか。
    通常の型付き DataTable は、TypedTableBase(Of ) を継承して作られますが、
    Web 参照等を通じて再生成された型付きDataTableは、素のDataTableから継承されるなど、
    微妙に動作が異なっていたりします。


    > データベース(postgres)をロード(テーブル80個)した
    問題が発生しているのは、New の部分なのですよね。

    型付きDataSet なら、スキーマの生成(Tables.Add や Columns.Add)は
    コンストラクタが呼ばれたタイミングで発生しますが、
    データの読みこみは、コンストラクタでは通常起こりません。

    New のタイミングではなく Clear のタイミングなら、
    データの処分コストがかかる気がしますが、提示されたコードには、
    データをロードしている箇所もありませんし。

    いずれにせよ、DataSet にとってみれば、元データが
    postgres (PostgreSQL?) かどうかは関係無いと思います。
    DataAdapter 等にとっては重要な情報ですが。


    > 状態では5000万回程度で100%発生します。
    (1) その「5000万回」という情報は、どのようにして確認されたものでしょうか。

    (2) 発生するのは 5000万を超えた後でしょうか。
    それとも 5000万の手前で発生するのでしょうか。
    正確な回数が分かれば、参考値としてお聞かせください。

    (3) 応答無しというのは、「Tick イベントがそもそも呼ばれない」事象でしょうか。
     それとも「Tick は呼ばれるが New の実行が完了しない」という事象でしょうか。

    (4) 応答が無くなってしまうというのは、具体的にはどの程度の時間だったのでしょうか。
    たとえば約90秒後に回復する現象だとか、あるいは回復後もパフォーマンスが低下するとか
    それとも、15分経っても完全に何も動きが無い状態になってしまっていただとか。
    (数十ミリ秒程度の停止なら、GC の稼動タイミングという可能性もありそうですが)


    > 毎回同じぐらいの回数で発生するので、何か解放漏れがあるのではないか?
    > と推測しています。
    そもそも事象を正確に掴めていないため、問題点を掴めていません。

    一応 DataSet の内部実装を追ってみましたが、現時点では特に思い当たりませんでした。
    https://referencesource.microsoft.com/#System.Data/System/Data/DataSet.cs

    気になるとすれば、型付きDataSet のコンストラクタで、スキーマの
    変更通知のイベントハンドラを割り当ていますが、それを剥がすコードが
    無いようでした。(これが問題になる事象かどうかは別として)


    ただ、NewRow メソッドについての、こんな投稿は見つかりました。
    http://d.hatena.ne.jp/genja/20090911/1252623184

    また、Clear しないとメモリが解放されないという投稿もありました。
    http://anton0825.hatenablog.com/entry/20110131/1296708900


    いずれも根拠が書かれていないので、根本理由までは不明ですが、
    仮に Clear すれば改善されるというのであれば、たとえば駄目元で
     dstData.Clear()
     dstData.Relations.Clear()
     dstData.Tables.Clear()
    のように、行だけではなくスキーマ情報も抹消してみては如何でしょう。
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81799  Re[4]: DataSetの破棄について
□投稿者/ sk -(2016/11/15(Tue) 11:45:46)
    ご返信ありがとうございます。
    以下インラインで回答させて頂きます。

    No81798 (魔界の仮面弁士 さん) に返信
    > ■No81789 (sk さん) に返信
    >>ただし、データセットに
    > 型付きDataSet を用いず、素の System.Data.DataSet に Tables.Add していった場合も
    > 同様の現象になるのでしょうか。

    確認できていないので、確認させていただきます。


    > また、その型付き DataSetは Webサービス等で公開されたものだったりはしないでしょうか。
    > 通常の型付き DataTable は、TypedTableBase(Of ) を継承して作られますが、
    > Web 参照等を通じて再生成された型付きDataTableは、素のDataTableから継承されるなど、
    > 微妙に動作が異なっていたりします。

    データセットはサーバエクスプローラと関連させたあとD&Dで作成しています。
    特に特殊なものではないと思っています。


    >>データベース(postgres)をロード(テーブル80個)した
    > 問題が発生しているのは、New の部分なのですよね。
    >
    > 型付きDataSet なら、スキーマの生成(Tables.Add や Columns.Add)は
    > コンストラクタが呼ばれたタイミングで発生しますが、
    > データの読みこみは、コンストラクタでは通常起こりません。
    >
    > New のタイミングではなく Clear のタイミングなら、
    > データの処分コストがかかる気がしますが、提示されたコードには、
    > データをロードしている箇所もありませんし。
    >
    > いずれにせよ、DataSet にとってみれば、元データが
    > postgres (PostgreSQL?) かどうかは関係無いと思います。
    > DataAdapter 等にとっては重要な情報ですが。

    DataSetのNew内のMe.InitClass()で止まってしまっています。
    (現象発生時、Me.InitClass()直後のログ出力がされていない。)


    >
    >>状態では5000万回程度で100%発生します。
    > (1) その「5000万回」という情報は、どのようにして確認されたものでしょうか。

    カウンタを用意して加算、ログ出力しています。


    > (2) 発生するのは 5000万を超えた後でしょうか。
    > それとも 5000万の手前で発生するのでしょうか。
    > 正確な回数が分かれば、参考値としてお聞かせください。

    以下の通りです。
    実際に業務で作成したプログラムでの回数
    1回目:54364159
    2回目:54364144
    3回目:54363946
    4回目:54366666

    投稿させていただいたサンプルプログラムでの回数
    1回目:53024288
    2回目:53024288


    > (3) 応答無しというのは、「Tick イベントがそもそも呼ばれない」事象でしょうか。
    >  それとも「Tick は呼ばれるが New の実行が完了しない」という事象でしょうか。

    Tickイベント内でNewが実行され、Newが完了せずそのまま応答なしになっている状態です。


    >
    > (4) 応答が無くなってしまうというのは、具体的にはどの程度の時間だったのでしょうか。
    > たとえば約90秒後に回復する現象だとか、あるいは回復後もパフォーマンスが低下するとか
    > それとも、15分経っても完全に何も動きが無い状態になってしまっていただとか。
    > (数十ミリ秒程度の停止なら、GC の稼動タイミングという可能性もありそうですが)

    1〜2日放置しても回復しなかったので、そのまま放置しても回復はしないと思います。


    >>毎回同じぐらいの回数で発生するので、何か解放漏れがあるのではないか?
    >>と推測しています。
    > そもそも事象を正確に掴めていないため、問題点を掴めていません。
    >
    > 一応 DataSet の内部実装を追ってみましたが、現時点では特に思い当たりませんでした。
    > https://referencesource.microsoft.com/#System.Data/System/Data/DataSet.cs
    >
    > 気になるとすれば、型付きDataSet のコンストラクタで、スキーマの
    > 変更通知のイベントハンドラを割り当ていますが、それを剥がすコードが
    > 無いようでした。(これが問題になる事象かどうかは別として)
    >
    >
    > ただ、NewRow メソッドについての、こんな投稿は見つかりました。
    > http://d.hatena.ne.jp/genja/20090911/1252623184
    >
    > また、Clear しないとメモリが解放されないという投稿もありました。
    > http://anton0825.hatenablog.com/entry/20110131/1296708900
    >
    >
    > いずれも根拠が書かれていないので、根本理由までは不明ですが、
    > 仮に Clear すれば改善されるというのであれば、たとえば駄目元で
    >  dstData.Clear()
    >  dstData.Relations.Clear()
    >  dstData.Tables.Clear()
    > のように、行だけではなくスキーマ情報も抹消してみては如何でしょう。

    ありがとうございます。
    上記の削除処理を入れて再度確認してみます。
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81801  Re[5]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/15(Tue) 14:45:37)
    No81799 (sk さん) に返信
    > DataSetのNew内のMe.InitClass()で止まってしまっています。
    > (現象発生時、Me.InitClass()直後のログ出力がされていない。)

    それはつまり、そもそも InitClass が呼び出されていない、ということでしょうか。
    それとも、InitClass 内のいずれかで停止している、ということでしょうか。

    仮に InitClass 内で時間がかかっているとしても、停止してしまうような
    処理には心当たりがありません。コンストラクタからの呼び出しなら尚の事。



    > 実際に業務で作成したプログラムでの回数
    > 投稿させていただいたサンプルプログラムでの回数

    検証時の参考にさせていただきます。

    ひとまず、下記条件の DataSet1 を作成して追検証中ですが、
    タイマー依存のテストなので、非常に時間がかかりますね…。

    ・DataSet 内に、テーブルを60個作成(DataTable1〜DataTable60)
    ・それぞれ、40個のテキスト列を実装(Column1〜Column40)
    ・各テーブルの Column40 は PrimaryKey として割り当て
    ・CaseSensitive = True
    ・EnforceConstraints = True
    ・RelationShip なし
    ・TableAdapter なし
    ・Timer1.Inerval = 1
    ・X64 ビルド
    ・VB2012 + .NET 4.6.1
    ・タスク優先度 = AboveNormal
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81807  Re[6]: DataSetの破棄について
□投稿者/ sk -(2016/11/15(Tue) 16:38:45)
    No81801 (魔界の仮面弁士 さん) に返信
    > ■No81799 (sk さん) に返信
    >>DataSetのNew内のMe.InitClass()で止まってしまっています。
    >>(現象発生時、Me.InitClass()直後のログ出力がされていない。)
    >
    > それはつまり、そもそも InitClass が呼び出されていない、ということでしょうか。
    > それとも、InitClass 内のいずれかで停止している、ということでしょうか。
    >
    > 仮に InitClass 内で時間がかかっているとしても、停止してしまうような
    > 処理には心当たりがありません。コンストラクタからの呼び出しなら尚の事。

    InitClass()をログで挟んだところ、直前のログが出力されていましたので、
    恐らくInitClass内のどこかで停止していると思われます。
    仮面弁士さんが心当たりがないということは、何か他に原因があるのでしょうか‥。


    >>実際に業務で作成したプログラムでの回数
    >>投稿させていただいたサンプルプログラムでの回数
    >
    > 検証時の参考にさせていただきます。
    >
    > ひとまず、下記条件の DataSet1 を作成して追検証中ですが、
    > タイマー依存のテストなので、非常に時間がかかりますね…。
    >
    > ・DataSet 内に、テーブルを60個作成(DataTable1〜DataTable60)
    > ・それぞれ、40個のテキスト列を実装(Column1〜Column40)
    > ・各テーブルの Column40 は PrimaryKey として割り当て
    > ・CaseSensitive = True
    > ・EnforceConstraints = True
    > ・RelationShip なし
    > ・TableAdapter なし
    > ・Timer1.Inerval = 1
    > ・X64 ビルド
    > ・VB2012 + .NET 4.6.1
    > ・タスク優先度 = AboveNormal

    わざわざありがとうございます。
    こちらも引き続き検証を行い、結果をご報告させていただきます。
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81810  Re[6]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/16(Wed) 10:04:20)
    No81801 (魔界の仮面弁士) に追記
    > ひとまず、下記条件の DataSet1 を作成して追検証中ですが、
    > タイマー依存のテストなので、非常に時間がかかりますね…。

    ここまで21時間回して450万回。5436万回の壁は遠いです。

    少なくとも現在の当方環境では、System.Windows.Forms.Timer の分解能が
    秒間64回(15.6ミリ秒間隔)程度しか無い様なので、結果が出るまでには
    10日はかかる見込みです。

    # timeBeginPeriod(1) は TIMERR_NOERROR を返したようだけど、効いていなかったかな。
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81812  Re[7]: DataSetの破棄について
□投稿者/ sk -(2016/11/16(Wed) 10:55:11)
    No81810 (魔界の仮面弁士 さん) に返信
    > ■No81801 (魔界の仮面弁士) に追記
    >>ひとまず、下記条件の DataSet1 を作成して追検証中ですが、
    >>タイマー依存のテストなので、非常に時間がかかりますね…。
    >
    > ここまで21時間回して450万回。5436万回の壁は遠いです。
    >
    > 少なくとも現在の当方環境では、System.Windows.Forms.Timer の分解能が
    > 秒間64回(15.6ミリ秒間隔)程度しか無い様なので、結果が出るまでには
    > 10日はかかる見込みです。
    >
    > # timeBeginPeriod(1) は TIMERR_NOERROR を返したようだけど、効いていなかったかな。

    申し訳ありません。
    こちらの検証環境では、以下のような処理で約2日強で発生しています。
    正確に記載せずに申し訳ありません。

    Timer1.Inerval = 10

    Private _intCount As Integer = 0
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

    for intLoop as integer = 0 to 100

    _intCount = _intCount + 1
    '※ログ出力処理

    Dim dstData As DataSet
    dstData = New DataSet1
    dstData.Clear()
    'dstData.Disposeでも結果は同じだった。

    Next

    End Sub
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81821  Re[8]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/16(Wed) 15:38:05)
    No81812 (sk さん) に返信
    > 申し訳ありません。
    > こちらの検証環境では、以下のような処理で約2日強で発生しています。
    
    そうでしたか。途中経過を報告して良かったです。
    
    だとすると、タイマー処理(WM_TIMER メッセージ)は関係なさそうなので、
    現在の計測は中止して、ワーカースレッドで無限ループさせる
    テスト手法に切り替えてみます。
    それでも 25 時間ほどかかりそうですが…。(^_^;)
    
    
    > for intLoop as integer = 0 to 100
    
    101 回のループですね。
    
    あまり元のコードを変えない方がよいのかも知れませんが、
    とりあえずこんな感じにしてみました。
    
    
    '---------------------
    Imports System.Threading
    Partial Public Class DataSet1
        Private Shared Log As String            'コンストラクター内の呼び出し履歴
        Private Shared InitClassLine As Integer 'InitClass 内の何行目まで進んだかをカウントアップ
    
        Friend Shared Function GetLog() As String
            Return "InitClass 内の行位置: " & InitClassLine.ToString("#,0") & vbCrLf & Log
        End Function
    
        ' <DebuggerNonUserCodeAttribute(), GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")> _
        Public Sub New()
            ' DataSet1.Designer.vb から移植
            MyBase.New()
            InitClassLine = 0
            Log = " DataSet1 : before [BeginInit()]" & vbCrLf
            Me.BeginInit()
            Log &= " DataSet1 : before [InitClass()]" & vbCrLf
            Me.InitClass()
            Log &= " DataSet1 : before [AddHandler()]" & vbCrLf
            Dim schemaChangedHandler As Global.System.ComponentModel.CollectionChangeEventHandler = AddressOf Me.SchemaChanged
            AddHandler MyBase.Tables.CollectionChanged, schemaChangedHandler
            AddHandler MyBase.Relations.CollectionChanged, schemaChangedHandler
            Log &= " DataSet1 : before [EndInit()]" & vbCrLf
            Me.EndInit()
            Log &= " DataSet1 : end of constructor" & vbCrLf
        End Sub
    
    #Region "Private Sub InitClass()"
        ' <DebuggerNonUserCodeAttribute(), GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")>
        Private Sub InitClass()
            InitClassLine = 1
            Me.DataSetName = "DataSet1"
            InitClassLine = 2
            Me.Prefix = ""
            InitClassLine = 3
            Me.Namespace = "http://tempuri.org/DataSet1.xsd"
            InitClassLine = 4
            Me.CaseSensitive = True
            InitClassLine = 5
            Me.EnforceConstraints = True
            InitClassLine = 6
            Me.SchemaSerializationMode = Global.System.Data.SchemaSerializationMode.IncludeSchema
            InitClassLine = 1010
            Me.tableSampleTable1 = New SampleTable1DataTable()
            InitClassLine = 1011
            MyBase.Tables.Add(Me.tableSampleTable1)
            InitClassLine = 1020
            Me.tableSampleTable2 = New SampleTable2DataTable()
            InitClassLine = 1021
            '--- 中略 ---
            InitClassLine = 1600
            Me.tableSampleTable60 = New SampleTable60DataTable()
            InitClassLine = 1601
            MyBase.Tables.Add(Me.tableSampleTable60)
            InitClassLine = 9999
        End Sub
    #End Region
    End Class
    
    '---------------------
    
    Imports System.Threading
    Imports System.ComponentModel
    
    Public Class Form1
        Private intCount As Integer = 0
        Private isBusy As Boolean = False
        Private cancel As Boolean = False
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            BackgroundWorker1.WorkerReportsProgress = True
            BackgroundWorker1.WorkerSupportsCancellation = True
            Button1.Text = "計測開始"
            Button2.Text = "計測中止"
            Button3.Text = "処理状況"
            Button1.Enabled = True
            Button2.Enabled = False
            Button3.Enabled = False
            TextBox1.ScrollBars = ScrollBars.Both
            TextBox1.Clear()
            Label1.Text = "開始待ち"
        End Sub
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            If isBusy Then
                e.Cancel = True
                MsgBox("計測中です", MsgBoxStyle.Exclamation)
            End If
        End Sub
    
        Private Function Test() As Integer
            Thread.CurrentThread.Priority = ThreadPriority.Highest
            Dim currentCount As Integer = intCount
            '101匹の大行進
            For dalmatians = 0 To 100
                currentCount = Interlocked.Increment(intCount)
    
                Dim dstData As DataSet
                dstData = New DataSet1
                dstData.Clear() 'とりあえず Using 無しでテスト
            Next
            Return currentCount
        End Function
    
        Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            isBusy = True
            Label1.Text = "計測中"
            Button1.Enabled = False
            Button2.Enabled = True
            Button3.Enabled = True
            Button1.Text = Now.ToString("HH:mm:ss.fff yyyy/MM/dd")
    
            Dim sw = Stopwatch.StartNew()
            Do
                Dim currentCount = Await Task.Run(AddressOf Test)
                Me.Text = currentCount.ToString("#,0") & "回経過 " & sw.Elapsed.ToString("c")
            Loop Until cancel
            sw.Stop()
            isBusy = False
            Label1.Text = "測定完了" & vbCrLf & sw.Elapsed.ToString("G")
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Button2.Enabled = False
            Label1.Text = "停止中"
            cancel = True
        End Sub
    
        Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
            Dim count = intCount
            TextBox1.Text = String.Format("{0:#,0}回目", count) & vbCrLf & DataSet1.GetLog()
        End Sub
    End Class
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81832  Re[9]: DataSetの破棄について
□投稿者/ sk -(2016/11/16(Wed) 18:00:01)
    No81821 (魔界の仮面弁士 さん) に返信
    > ■No81812 (sk さん) に返信

    > あまり元のコードを変えない方がよいのかも知れませんが、
    > とりあえずこんな感じにしてみました。

    ありがとうございます。
    こちらの環境でも同様の仕組みで動作を開始してみます。
    (そちらで現象が発生しなかった場合の切り分け材料の一つとして)


    > 'とりあえず Using 無しでテスト

    ちなみに、Usingを使用してもこちらの環境では結果は同じでした。
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81875  Re[10]: DataSetの破棄について
□投稿者/ sk -(2016/11/18(Fri) 16:38:42)
    No81798 (魔界の仮面弁士 さん) に返信
    > ■No81789 (sk さん) に返信
    >>ただし、データセットに
    > 型付きDataSet を用いず、素の System.Data.DataSet に Tables.Add していった場合も
    > 同様の現象になるのでしょうか。

    只今、検証中です。


    > いずれも根拠が書かれていないので、根本理由までは不明ですが、
    > 仮に Clear すれば改善されるというのであれば、たとえば駄目元で
    >  dstData.Clear()
    >  dstData.Relations.Clear()
    >  dstData.Tables.Clear()
    > のように、行だけではなくスキーマ情報も抹消してみては如何でしょう。

    スキーマ情報を削除するようにしましたが、53,024,288回で停止しました。


    > あまり元のコードを変えない方がよいのかも知れませんが、
    > とりあえずこんな感じにしてみました。

    仮面弁士さんから頂いたソースを組み込んだところやはり停止してしまいました。
    結果は以下の通りです。

    53,024,288回目
    InitClass 内の行位置: 1,460
    DataSet1 : before [BeginInit()]
    DataSet1 : before [InitClass()]

    コード抜粋
        ‥
    MyBase.Tables.Add(テーブル1)
    InitClassLine = 1460
    Me.tabled_テーブル2 = New テーブル2DataTable
        ‥


    以上、経過報告まで。
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81879  Re[11]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/18(Fri) 17:06:04)
    No81875 (sk さん) に返信
    >>あまり元のコードを変えない方がよいのかも知れませんが、
    >>とりあえずこんな感じにしてみました。
    > 仮面弁士さんから頂いたソースを組み込んだところやはり停止してしまいました。

    こちらは現状、動き続けてますね…。

    25時間25分ほど経過した段階の途中経過がこんな感じ。

    58,556,557回目
    InitClass 内の行位置: 9,999
    DataSet1 : before [BeginInit()]
    DataSet1 : before [InitClass()]
    DataSet1 : before [AddHandler()]
    DataSet1 : before [EndInit()]
    DataSet1 : end of constructor
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81883  Re[12]: DataSetの破棄について
□投稿者/ sk -(2016/11/18(Fri) 17:40:21)
    No81879 (魔界の仮面弁士 さん) に返信
    > ■No81875 (sk さん) に返信
    > >>あまり元のコードを変えない方がよいのかも知れませんが、
    > >>とりあえずこんな感じにしてみました。
    >>仮面弁士さんから頂いたソースを組み込んだところやはり停止してしまいました。
    >
    > こちらは現状、動き続けてますね…。

    そうですか‥‥

    今回こちらでは、今までと違うOS(7)で動作させたにも関わらず「53,024,288回」という
    ぴったり回数で停止したので、環境に依存はしないと想定します。(希望)
    あと違いを考えると、Tableの個数が違いますので、Table数に比例している(?)とすると、
    仮面弁士さんの環境では「66,280,240回」ぐらいで発生する(?)かもしれません。
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81887  Re[13]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/18(Fri) 20:01:01)
    2016/11/18(Fri) 21:04:04 編集(投稿者)

    No81883 (sk さん) に返信
    >>こちらは現状、動き続けてますね…。
    > 今回こちらでは、今までと違うOS(7)で動作させたにも関わらず「53,024,288回」という
    > ぴったり回数で停止したので、環境に依存はしないと想定します。(希望)


    古い情報ですが、こんな投稿がありました。


    [継承したコントロールのメモリの解放]
    http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=47943&forum=7

    》 投稿日時: 2009-01-21 10:06
    》 これ、Release モードだと発生しませんね。


    当方では Release ビルドの EXE で実行させていますので、
    再現しないかも知れません。


    》 投稿日時: 2009-02-18 01:13
    》 どうも最適化を有効にしない場合は、VBコンパイラが
    》 作成したクラスのコンストラクタに以下のようなコードを挿入していますね。

    》 <DebuggerNonUserCode> _
    》 Public Sub New()
    》   Dim list As List(Of WeakReference) = CustomDataSet.__ENCList
    》   SyncLock list
    》     CustomDataSet.__ENCList.Add(New WeakReference(Me))
    》   End SyncLock
    》 End Sub


    __ENCList というと、Edit & Continue のヘルパーですね。

    その方向で検索してみたら、こんな記事が見つかりました。
    https://support.microsoft.com/ja-jp/kb/919481

    このあたりは VS2010 で改善されているそうなので、
    関係ないかも知れませんが、一応参考までに。


    ---
    追記:DataSet の弱参照に関して、こんな記事もありました。
    内容的には上記と同じかな。

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/b83106bd-8afe-4291-8620-f173e214cd23/weakreferences-in-a-debug-build?forum=clr
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81889  Re[14]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/18(Fri) 21:45:18)
    2016/11/18(Fri) 21:49:56 編集(投稿者)

    No81887 (魔界の仮面弁士) に追記
    > 当方では Release ビルドの EXE で実行させていますので、
    > 再現しないかも知れません。

    No81821 で作った DataSet1 を逆コンパイルしてみました。
    IL のままだと読み難いので、VB コードに置き換えています。


    <Releaseビルド>
    Public Sub New()
     Me._schemaSerializationMode = SchemaSerializationMode.IncludeSchema
     DataSet1.InitClassLine = 0
     DataSet1.Log = " DataSet1 : before [BeginInit()]" & vbCrLf
     Me.BeginInit()
     以下略


    <Debugビルド>
    Private Shared __ENCList As New List<WeakReference>();
    Public Sub New()
     DataSet1.__ENCAddToList(Me) '★
     Me._schemaSerializationMode = SchemaSerializationMode.IncludeSchema
     DataSet1.InitClassLine = 0
     DataSet1.Log = " DataSet1 : before [BeginInit()]" & vbCrLf
     Me.BeginInit()
     以下略


    VB2012 でも起こりえるようです。
    https://social.msdn.microsoft.com/Forums/en-US/a304a4d5-660d-4df2-a40d-1d6ca76b8e62/contractclassforattribute-and-encaddtolist?forum=codecontracts


    ――ということで、現段階の私の見解としては:

    Event を持つクラスを、VB.NET で Debug ビルドした場合、
    Edit & Continue の仕組みのために、WeakReference なリストに
    そのインスタンスが保持されるようになっているため、超高頻度で
    大量にインスタンス化した場合には、GC 回収が間に合わずに
    メモリを圧迫する結果になりえる。それが今回の「停止」の要因となった。

    ――と予想してみました。

    まぁ、当方環境にて Debug ビルドな動作テストを行ったわけでも無いですし、
    Event の無いクラスでどうなるのかも調べていないので、確証は無いですが。


    # でもこのパターンなら、動作が停止するのではなく、例外で通達されるか、
    # プロセス自体が落とされる事態になっても良いような気がする…。
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81892  Re[15]: DataSetの破棄について
□投稿者/ sk -(2016/11/18(Fri) 23:11:03)
    No81889 (魔界の仮面弁士 さん) に返信
    > 2016/11/18(Fri) 21:49:56 編集(投稿者)

    > Event を持つクラスを、VB.NET で Debug ビルドした場合、
    > Edit & Continue の仕組みのために、WeakReference なリストに
    > そのインスタンスが保持されるようになっているため、超高頻度で
    > 大量にインスタンス化した場合には、GC 回収が間に合わずに
    > メモリを圧迫する結果になりえる。それが今回の「停止」の要因となった。
    >
    > ――と予想してみました。

    DebugビルドとReleaseビルドでそのような違いがあるとは知りませんでした。
    今回確認用として作成したサンプルプログラムは
    Debugビルドで作成しているので、上記要因に当たる可能性は十分あると思います。
    しかし、実際業務で作成しているものはReleaseでビルドしていますので
    要因としては・・と思います。
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81900  Re[12]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/21(Mon) 10:36:22)
    No81879 (魔界の仮面弁士 さん) に返信
    > こちらは現状、動き続けてますね…。
    > 25時間25分ほど経過した段階の途中経過がこんな感じ。
    > 58,556,557回目
    
    再現しました。
    Release ビルドにおいて、60時間22分58秒後 に停止しています。
    
    71,582,789回目
    InitClass 内の行位置: 1,120
     DataSet1 : before [BeginInit()]
     DataSet1 : before [InitClass()]
    
    
    [処理状況]ボタンは反応するので、UI スレッドは生きているようですが、
    ワーカースレッドは、DataSet1 の初期化プロセスの
     Me.tableSampleTable12 = New DataSet1.SampleTable12DataTable()
    を完了できない状態です。
    # おかげで、[計測中止]ボタンを押しても停止処理が完了しない…。
    
    
    一応、メモリ使用状況を記載しておきます。
    計測中、継続的に監視していたわけではないので、分かるのは
    停止時点の最終値のログだけです。(最小値=最大値な状態)
    
    
    ===== Virtual Memory =====
         31,872 KB          Private Bytes
         38,380 KB          Peak Private Bytes
        670,208 KB          Virtual Size
    253,837,243 回          Page Faults
              0 回          Page Fault Delta
    
    ===== Handles =====
            187 個          Handles
            211 個          Peak Handles
             62 個          GDI Handles
             36 個          USER Handles
    
    ===== .NET CLR Memory =====
        586,768 バイト      # Bytes in all Heaps
          1,370 個          # GC Handles
     20,519,820 回          # Gen 0 Collections
     10,076,826 回          # Gen 1 Collections
        337,649 回          # Gen 2 Collections
              0 回          # Induced GC
              1 個          # of Pinned Objects
             18 個          # of Sink Blocks in use
      3,731,456 バイト      # Total committed Bytes
    402,644,992 バイト      # Total reserved Bytes
              0 %          % Time in GC
              0 バイト/秒  Allocated Bytes/Second
              0 個          Finalization Survivors
      3,145,727 バイト      Gen 0 heap size
              0 バイト/秒  Gen 0 Promoted Bytes/Sec
             24 バイト      Gen 1 heap size
              0 バイト/秒  Gen 1 Promoted Bytes/Sec
        516,800 バイト      Gen 2 heap size
         69,944 バイト      Large Object Heap size
              0 バイト      Promoted Finalization-Memory from Gen 0
              0 バイト      Promoted Memory from Gen 0
             56 バイト      Promoted Memory from Gen 1
    
    ===== .NET CLR Loading =====
            169 個          Total Classes Loaded
      1,499,136 バイト      Bytes in Loader Heap
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81901  Re[13]: DataSetの破棄について
□投稿者/ sk -(2016/11/21(Mon) 13:06:57)
    No81900 (魔界の仮面弁士 さん) に返信
    > ■No81879 (魔界の仮面弁士 さん) に返信

    > 再現しました。
    > Release ビルドにおいて、60時間22分58秒後 に停止しています。

    再現してしまいましたか・・。


    > 型付きDataSet を用いず、素の System.Data.DataSet に Tables.Add していった場合も
    > 同様の現象になるのでしょうか。

    素のdatasetというわけではありませんが、テーブルデザインからadapterを削除した
    もので確認してみましたが、結果は変わらず53,024,288回で停止していました。
    引き続きdatasetにaddした素のdatasetで確認してみます。

記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

■81921  Re[14]: DataSetの破棄について
□投稿者/ 魔界の仮面弁士 -(2016/11/24(Thu) 09:39:27)
    No81901 (sk さん) に返信
    >>Release ビルドにおいて、60時間22分58秒後 に停止しています。
    > 再現してしまいましたか・・。

    タイマーを使わずに無限ループさせてみましたが、やはり 57時間ともたずに、
    型付きな DataSet1 生成が停止してしまいました。

    今回はコンソールアプリとしての実行です。

    -----------------
    71,582,789 回目
    InitClass 内の行位置: 1,150 …… DataSet1 内の15個目のテーブルをNewしている最中
    DataSet1 : before [BeginInit()]
    DataSet1 : before [InitClass()]

    -----------------

    ※実行回数 71,582,720 時点の累積時間は 2日と8時間56分59秒4931635

    コンストラクタが完了待ちのままになっているというだけであり、プロセス自体は
    停止していません。Console.CancelKeyPress イベントによる割り込みは可能でした。


    また、今回の検証時、GC.GetTotalMemory も計測していましたが、
    常時、数 MB というサイズを維持して上下動しており、
    GC が間に合っていないというわけでもなさそうに思えます。

    GC.GetTotalMemory の最小値は 70,796
    最大値でも 7,96,084 という結果です。

    処理停止後の GC.GetTotalMemory は 3,524,268 バイトでしたが、
    停止後に GC を強制発動してみたところ、242,412 バイトまで減少しました。
    それでもプログラムが再開する様子はありません。


    参考までに、今回の計測プログラムを掲載しておきます。

    Imports System
    Imports System.Data
    Imports System.Diagnostics
    Imports System.Linq
    Imports System.Threading

    '1 = 型付 DataSet で検証
    '2 = 素の DataSet で検証
    #Const TYPED_DATASET = 1

    Module Module1
     Private Cancel As Boolean = False
     Private Const LoopMax As Integer = 256 '連続生成数

     Private _i As Integer '処理回数

     ''' <summary>ログ出力</summary>
    #If TYPED_DATASET = 1 Then
     Private Function GetLog() As String
      Return _i.ToString("#,0") & " 回目" & vbCrLf &
        DataSet1.GetLog()
     End Function
    #Else
     Private Function GetLog() As String
      Return _i.ToString("#,0") & " 回目" & vbCrLf &
        "Table:" & _table.ToString("#,0") & vbCrLf & "Column:" & _column.ToString("#,0")
     End Function
     Private Const TableCount As Integer = 60
     Private Const ColumnCount As Integer = 80
     Private _Log As String
     Private _table As Integer
     Private _column As Integer
    #End If

     Sub Main()
      '[Break] もしくは [Ctrl]+[C] で割りこみ処理
      AddHandler Console.CancelKeyPress, _
       Sub(sender, e)
        Dim msg = "中止   => 計測停止" & vbCrLf &
           "再試行  => GC.Collect を発動して継続" & vbCrLf &
           "キャンセル => (何もしない)" & vbCrLf
        Dim style = vbAbortRetryIgnore Or vbQuestion Or vbDefaultButton3 Or vbMsgBoxSetForeground
        Select Case MsgBox(msg & vbCrLf & GetLog(), style)
         Case vbAbort
          Cancel = True
         Case vbRetry
          Dim before = GC.GetTotalMemory(False)
          GC.Collect()
          GC.WaitForPendingFinalizers()
          GC.Collect()
          Dim after = GC.GetTotalMemory(True)
          MsgBox("GC結果" & vbCrLf & String.Format(
            "発動前: {0,15:#,0}" & vbCrLf & "発動後: {1,15:#,0}",
            before, after), vbInformation)
         Case vbIgnore
          REM DoNothing
        End Select
        e.Cancel = True
       End Sub

      '負荷テスト
      Do
       Module1._i = 0
       Dim curMem As Long = 0
       Dim minMem As Long = Long.MaxValue
       Dim maxMem As Long = Long.MinValue
       Dim sw As Stopwatch = Stopwatch.StartNew()
       Cancel = False
       While Module1._i < (Int32.MaxValue - LoopMax)
        Dim counter = String.Format("実行回数 {0,-16:#,0}" & vbTab, Module1._i)

        Console.SetCursorPosition(0, 0)
        Console.WriteLine(counter)
        Console.WriteLine("現在時刻 " & Now.ToString("yyyy/MM/dd HH:mm:ss.fffffff"))
        Console.WriteLine("累積時間 " & sw.Elapsed.ToString("G"))
        Dim oldMem = GC.GetTotalMemory(False)
        minMem = Math.Min(oldMem, minMem)
        maxMem = Math.Max(oldMem, maxMem)
        Console.WriteLine()
        For j = 1 To LoopMax
         Module1._i += 1
         Dim ds As DataSet
    #If TYPED_DATASET = 1 Then
         ds = New DataSet1()
         If Cancel Then Exit While
    #Else
         _Log = " before New DataSet()" & vbCrLf
         ds = New DataSet()
         ds.EnforceConstraints = False
         For Module1._table = 1 To TableCount
          Dim tblName = "Table" & Module1._table.ToString("0000")
          Dim tbl As New DataTable(tblName)
          For Module1._column = 1 To ColumnCount
           Dim colName = "Column" & Module1._column.ToString("000")
           Dim col As New DataColumn(colName)
           tbl.Columns.Add(col)
          Next
          ds.Tables.Add(tbl)
          If Cancel Then Exit While
         Next
         ds.EnforceConstraints = True
         _Log &= " before Clear()" & vbCrLf
    #End If
         ds.Clear()
        Next
        Dim newMem = GC.GetTotalMemory(False)
        minMem = Math.Min(newMem, minMem)
        maxMem = Math.Max(newMem, maxMem)
        Console.WriteLine("使用容量 {0,-40}", String.Format("{0:#,0} => {1:#,0}", oldMem, newMem))
        Console.WriteLine()
        Console.WriteLine("最低 {0,-15:#,0}", minMem)
        Console.WriteLine("最高 {0,-15:#,0}", maxMem)
       End While
       Console.SetCursorPosition(0, 10)
       Console.WriteLine(If(Cancel, "キャンセル", "ループ終了"))
       Console.WriteLine(GetLog())
       Console.WriteLine("現在時刻 " & Now.ToString("yyyy/MM/dd HH:mm:ss.fffffff"))
      Loop While MsgBoxResult.Yes = MsgBox("もう一度最初から?", vbYesNo Or vbQuestion)

      Console.SetCursorPosition(0, 21)
      Console.WriteLine("Hit Any Key...")
      Console.ReadKey()
     End Sub

    End Module
記事No.81781 のレス /過去ログ140より / 関連記事表示
削除チェック/

次の20件>

<< 0 | 1 >>

パスワード/

- Child Tree -