LINQサブミッチャンガンはメモリがなくなります
-
28-09-2019 - |
質問
約180,000のレコードがあるデータベースがあります。 PDFファイルを各レコードに添付しようとしています。各PDFのサイズは約250 kbです。しかし、約1分後、私のプログラムは約GBのメモリを取り始め、それを止めなければなりません。私はそれを試してみましたので、各linqオブジェクトへの参照が更新されると削除されますが、それは役に立たないようです。参照を明確にするにはどうすればよいですか?
ご協力いただきありがとうございます
Private Sub uploadPDFs(ByVal args() As String)
Dim indexFiles = (From indexFile In dataContext.IndexFiles
Where indexFile.PDFContent = Nothing
Order By indexFile.PDFFolder).ToList
Dim currentDirectory As IO.DirectoryInfo
Dim currentFile As IO.FileInfo
Dim tempIndexFile As IndexFile
While indexFiles.Count > 0
tempIndexFile = indexFiles(0)
indexFiles = indexFiles.Skip(1).ToList
currentDirectory = 'I set the directory that I need
currentFile = 'I get the file that I need
writePDF(currentDirectory, currentFile, tempIndexFile)
End While
End Sub
Private Sub writePDF(ByVal directory As IO.DirectoryInfo, ByVal file As IO.FileInfo, ByVal indexFile As IndexFile)
Dim bytes() As Byte
bytes = getFileStream(file)
indexFile.PDFContent = bytes
dataContext.SubmitChanges()
counter += 1
If counter Mod 10 = 0 Then Console.WriteLine(" saved file " & file.Name & " at " & directory.Name)
End Sub
Private Function getFileStream(ByVal fileInfo As IO.FileInfo) As Byte()
Dim fileStream = fileInfo.OpenRead()
Dim bytesLength As Long = fileStream.Length
Dim bytes(bytesLength) As Byte
fileStream.Read(bytes, 0, bytesLength)
fileStream.Close()
Return bytes
End Function
解決
これを使用してバッチで実行することをお勧めします Take
(前 通話 ToList
)特定の数のアイテムを一度に処理する。読む(たとえば)10、設定します PDFContent
の上 すべて それらの、電話してください SubmitChanges
, 、それからもう一度始めます。 (新しいから始めるべきかどうかはわかりません DataContext
その時点で、しかしそうするのは最もきれいかもしれません。)
余談ですが、ファイルの内容を読み取るコードは少なくともいくつかの方法で壊れていますが、使用するだけで簡単です File.ReadAllBytes
そもそも。
また、リストを徐々に縮小する方法は非常に非効率的です。180,000のレコードを取得した後、179,999のレコードで新しいリストを作成し、179,998のレコードなどを備えた別のリストを作成します。
他のヒント
DataContextには、objectTrackingEnabledがtrue(デフォルト値)に設定されていますか?もしそうなら、それはそれが触れる本質的にすべてのデータの記録を保持しようとするので、したがって、ガベージコレクターがそれのいずれかを収集することができなくなります。
その場合、定期的にDataContextを処分し、新しいものを作成するか、オブジェクトを追跡することにより、状況を修正できるはずです。
わかった。最小のメモリを使用するには、ブロックでデータコンテキストを更新する必要があります。以下にサンプルコードを掲載しました。メモ帳を使用して入力するため、システム型エラーがある可能性があります。
Dim DB as YourDataContext = new YourDataContext
Dim BlockSize as integer = 25
Dim AllItems = DB.Items.Where(function(i) i.PDFfile.HasValue=False)
Dim count = 0
Dim tmpDB as YourDataContext = new YourDataContext
While (count < AllITems.Count)
Dim _item = tmpDB.Items.Single(function(i) i.recordID=AllItems.Item(count).recordID)
_item.PDF = GetPDF()
Count +=1
if count mod BlockSize = 0 or count = AllItems.Count then
tmpDB.SubmitChanges()
tmpDB = new YourDataContext
GC.Collect()
end if
End While
速度をさらに最適化するために、AllItemsの匿名タイプとしてAllitemsの配列にRecordIDを入力し、そのPDFフィールドの遅延ロードを設定できます。