ConcurrentQueue Disposed nicht

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von Twometer.

    ConcurrentQueue Disposed nicht

    Hi Leute,
    ich bin grade dabei einen Screen-Recorder zu programmieren, was auch soweit recht gut funktioniert. Dazu habe ich das Konzept: Thread 1 nimmt auf Thread 2 speichert auf der Platte. Dazu verwende ich ne ConcurrentQueue(Of Image). Jetzt läuft aber trotz versuche mit Dispose und GC.Collect() mir nach ~20 Sekunden der RAM über ==> OutOfMemoryException.
    Mein Code ist der hier:

    VB.NET-Quellcode

    1. Dim saverThread As New Thread(AddressOf DoWorkSave)
    2. Dim takerThread As New Thread(AddressOf DoWorkTake)
    3. Dim imgList As New ConcurrentQueue(Of Image)
    4. [...]
    5. Private Sub DoWorkSave()
    6. While True
    7. Dim itm As Image
    8. If imgList.Count <> 0 AndAlso imgList.TryDequeue(itm) Then
    9. itm.Save("C:\ScreenRecTemp\" + imgCounter.ToString + ".png", ImageFormat.Png)
    10. imgCounter += 1
    11. itm.Dispose()
    12. End If
    13. If imgList.Count = 0 And Not threadRunning Then
    14. Exit While
    15. End If
    16. End While
    17. saverThread.Join()
    18. End Sub
    19. Private Sub DoWorkTake()
    20. While threadRunning
    21. Dim x = CaptureScreen.CaptureDesktopWithCursor
    22. If x IsNot Nothing Then
    23. frames += 1
    24. allFrames += frames
    25. allFramesCount += 1
    26. imgList.Enqueue(x)
    27. End If
    28. End While
    29. takerThread.Join()
    30. End Sub


    Das Lustige ist, das passiert erst, sobald ich VS auf den 2. Monitor ziehe von mir ?(

    Btw An CaptureScreen.CaptureDesktopWithCursor liegts nich weil ich habe mitm VS Profiler herausgefunden das es die Queue ist.


    Hoffe ihr könnt mir Helfen :D
    EDIT: Ohne den Debugger läufts einwandfrei bei ~13MB RAM verbrauch xD
    LG
    Twometer
    An Error 404 occurred while loading signature...
    Ich vermute jetzt einfach mal ins Blaue, dass der eine Thread so viele Bilder in die Liste schaufelt, dass der andere Thread nicht mehr mit Speichern hinterherkommt. Das ist auch nicht weit hergeholt, denn ich sehe da nichts, was festlegt, wie viele Screenshots pro Sekunde gemacht werden sollen. Der Thread rattert einfach vollgas dahin.
    Jetzt wäre gut, mal herauszufinden, ob das das Problem ist.
    Starte einfach mal einen WinForms-Timer (ich nehme an, dass Du WinForms verwendest, ansonsten halt den DispatcherTimer) mit einem Intervall von ca. 1000 (Millisekunden). Im Tick-EventHandler sagst Du dann Me.Text = imgList.Count.ToString (bzw. Me.Title bei WPF).
    Wenn die Zahl immer größer wird, ist klar, dass zu viele Screenshots erstellt werden. Ansonsten liegt das Problem woanders (aber Du solltest trotzdem einen Timer (vermutlich System.Threading.Timer) verwenden, um regelmäßig Screenshots zu machen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Hi,
    erstmal danke für die schnelle Antwort :)
    ich habe vorher einen Timer gehabt, da hatte sich auch nichts geändert. Da wars genauso schlimm (Hatte den Timer aber nur auf 1ms xD) Aber das komische ist ja, dass der RAM am Anfang immer so bei ~20 MB bleibt. wenn ich dann im debugger VS auf meinen 2. Bildschirm ziehe steigt die Kurve wie folgt an:


    Auch als ich mal ne längere zeit ohne Debugger aufgenommen habe, kam nach ner Zeit "ScreenRecorder funktioniert nicht mehr".
    Ich verstehe das nicht so wirklich ;(

    LG
    Twometer
    An Error 404 occurred while loading signature...
    Hi,
    ich habe mit dem VS 2015 Profiler geguckt, da steht 200 items in der ConcurrentQueue zu je 10.000 kb (gesamt 2GB) und der disposed nicht. Das Problem ist ja, das passiert, wenn der Debugger angeschlossen ist, nur wenn VS auf dem 2. Bildschirm ist nach 10sek (siehe BIld mit der Kurve), ansonsten wenn ichs direkt ausführe gehts so ~1min und dann "ScreenRecorder funktioniert nicht mehr". Ich kann, wenn ich zu Hause an den PC kommme, den Code von CaptureScreen.CaptureDesktopWithCursor() hier mal posten

    LG
    Twometer
    An Error 404 occurred while loading signature...
    Das Problem liegt mit hoher Wahrscheinlichkeit nicht daran, dass der Debugger angeschlossen ist, oder dass Du Visual Studio umherziehst.
    Das Problem liegt daran, dass Du was die Kiste hergibt Screenshots produzierst und die sich im RAM sammeln, wenn sie nicht schnell genug auf die Platte geschrieben werden können.
    Du solltest erst mal zusehen, dass Du Dir ein gutes System überlegst für:
    1. Wie mache ich Screenshots in einem fixen Intervall?
    2. Wie mache ich Screenshots in einem fixen Intervall in einem Nebenthread?
    3. Wie schreibe ich die Screenshots auf Platte?
    4. Wie stelle ich sicher, dass nie mehr als eine maximale Anzahl an Screenshots gleichzeitig im Arbeitsspeicher liegen? Und damit zusammenhängend:
    5. Was mache ich mit Screenshots, die ich nicht schnell genug verarbeiten kann?
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Hi,
    ich habs jetzt so gemacht:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub DoWorkTake()
    2. While threadRunning
    3. CaptureScreen.CaptureDesktopWithCursor()
    4. Dim img = CaptureScreen.currentDesktop
    5. If img IsNot Nothing Then
    6. frames += 1
    7. allFrames += frames
    8. allFramesCount += 1
    9. imgList.Enqueue(img)
    10. End If
    11. Thread.Sleep(5)
    12. End While
    13. End Sub



    Jetzt dauert es zwar länger bis der RAM anfängt zu steigen, aber wenn VS auf dem 2. Bildschirm ist, steigt die kurve, wenn ich VS zurück auf den 1. schiebe, fällt der RAM-Verbrauch wieder ab :O

    ich mein überprüfen kann ich das wenn ich hinzufüge, dass er guckt ob imgList.count > 150 oder so ist, dass er dann aufhört und langsamer macht oder die zu vielen speichert, bevor er weitermacht.

    Mein Problem ist halt, dass das so komisch aufttritt (Wenn debugger maximiert auf 2. bildschirm oder so komisches zeug)

    //EDIT: Mit 20ms hab ich getestet dauert es zwar viel länger, weil weniger bilder gemacht werden, aber der ram steigt aufm 2. screen und sinkt aufm 1.

    //EDIT2: Hier noch der Code von CaptureScreen (ist ausm Internet wegen WINAPI und aus c# übersetzt)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Structure SIZE
    2. Public cx As Integer
    3. Public cy As Integer
    4. End Structure
    5. Private Shared Function CaptureDesktop() As Bitmap
    6. Dim size As SIZE
    7. Dim hBitmap As IntPtr
    8. Dim hDC As IntPtr = Win32Stuff.GetDC(Win32Stuff.GetDesktopWindow())
    9. Dim hMemDC As IntPtr = GDIStuff.CreateCompatibleDC(hDC)
    10. size.cx = Win32Stuff.GetSystemMetrics(Win32Stuff.SM_CXSCREEN)
    11. size.cy = Win32Stuff.GetSystemMetrics(Win32Stuff.SM_CYSCREEN)
    12. hBitmap = GDIStuff.CreateCompatibleBitmap(hDC, size.cx, size.cy)
    13. If hBitmap <> IntPtr.Zero Then
    14. Dim hOld As IntPtr = GDIStuff.SelectObject(hMemDC, hBitmap)
    15. GDIStuff.BitBlt(hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, GDIStuff.SRCCOPY)
    16. GDIStuff.SelectObject(hMemDC, hOld)
    17. GDIStuff.DeleteDC(hMemDC)
    18. Win32Stuff.ReleaseDC(Win32Stuff.GetDesktopWindow(), hDC)
    19. Dim bmp As Bitmap = Image.FromHbitmap(hBitmap)
    20. GDIStuff.DeleteObject(hBitmap)
    21. Return bmp
    22. End If
    23. Return Nothing
    24. End Function
    25. Private Shared Function CaptureCursor(ByRef x As Integer, ByRef y As Integer) As Bitmap
    26. Dim bmp As Bitmap
    27. Dim hicon As IntPtr
    28. Dim ci As New Win32Stuff.CURSORINFO()
    29. Dim icInfo As Win32Stuff.ICONINFO
    30. ci.cbSize = Marshal.SizeOf(ci)
    31. If Win32Stuff.GetCursorInfo(ci) Then
    32. If ci.flags = Win32Stuff.CURSOR_SHOWING Then
    33. hicon = Win32Stuff.CopyIcon(ci.hCursor)
    34. If Win32Stuff.GetIconInfo(hicon, icInfo) Then
    35. x = ci.ptScreenPos.x - CInt(icInfo.xHotspot)
    36. y = ci.ptScreenPos.y - CInt(icInfo.yHotspot)
    37. Try
    38. Dim ic As Icon = Icon.FromHandle(hicon)
    39. bmp = ic.ToBitmap()
    40. Return bmp
    41. Catch ex As Exception
    42. Return Nothing
    43. End Try
    44. End If
    45. End If
    46. End If
    47. Return Nothing
    48. End Function
    49. Public Shared currentDesktop As Bitmap
    50. Public Shared Function CaptureDesktopWithCursor() As Bitmap
    51. Dim cursorX As Integer = 0
    52. Dim cursorY As Integer = 0
    53. Dim desktopBMP As Bitmap
    54. Dim cursorBMP As Bitmap
    55. Dim g As Graphics
    56. Dim r As Rectangle
    57. desktopBMP = CaptureDesktop()
    58. cursorBMP = CaptureCursor(cursorX, cursorY)
    59. If desktopBMP IsNot Nothing Then
    60. If cursorBMP IsNot Nothing Then
    61. r = New Rectangle(cursorX, cursorY, cursorBMP.Width, cursorBMP.Height)
    62. g = Graphics.FromImage(desktopBMP)
    63. g.DrawImage(cursorBMP, r)
    64. g.Flush()
    65. currentDesktop = desktopBMP.Clone
    66. g.Dispose()
    67. End If
    68. End If
    69. desktopBMP.Dispose()
    70. cursorBMP.Dispose()
    71. Return Nothing
    72. End Function
    73. End Class



    //EDIT3: Das Problem ist grade von 1sek auf die andere verschwunden ?(

    //EDIT4: Nachdem ich den post geschrieben habe, war es wieder da

    und ich mache ja nur screenshots vom 1. (also vom Haupt) Bildschirm

    LG
    Twometer
    An Error 404 occurred while loading signature...

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Twometer“ ()