Results 1 to 37 of 37

Thread: Threading and leaking memory - a demonstration

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Threading and leaking memory - a demonstration

    There's a good deal of web chatter regarding VS/CLR threading creating memory management problems. Specifically, the issue seems to be that overactive threading creates noticeable memory leak issues.

    I'm sorry to say that this is consistent with what I'm seeing as I add multi-threading to my current app.

    For the guru's, attached please find a small project demonstrating the issue. It's pretty simple. It has one form, one button and one label. It has a class that manages a run/control loop and another that is run by the control loop. (This structure mimmicks my production code.) I suggest running it in the debugger. Don't know what it might perpetrate in the real world.

    I'm currently running VS2008 under Vista in a 32 bit environment.

    On my machine (a 2.4 gig, 4 core AMD with 16 gig mem - using only 4 of course), this locks after ~7k repeats (running the test is a good excuse to refresh the coffee input device). Not that there could be any doubt, but I am no longer any sort of kernel guru. However, using Process Explorer (http://technet.microsoft.com/en-us/s.../bb896653.aspx ), I was able to determine that in the end, this program dies trying to make a memory allocation associated with a thread creation. Between this and the fact that the run of the program shows a slight but noticeable upward trend in memory utilization, AND that my production program sucks down the memory like a black hole when running in multi thread mode (much bigger classes/routines), I conclude that memory is leaking.

    My questions:
    1) Do you have any suggestions for fixing the current style of thread use? (i.e. changing where the threads are declared, calling System.GC, doing something with Finalize, setting the thread to Nothing on completion, etc.) I've tried a number of these but I'm sure this audience will have more than I've thought of.

    2) Does anyone know off hand if using a Threadpool mitigates this problem?

    3) Any ideas (hopefully fairly simple) that would allow me to multi-thread (or process for that matter) that don't kill the OS environment.

    If you really want to check this out and/or help and have only a 2005 environment, let me know and I'll build a version and upload it.

    Thanks in advance.

    PS. Please forgive in advance if there's a simple fix/explanation for this someplace. As I said above, I've googled this at some length and find a great many questions but a noticeable lack of answers. In that case, just point me to it!
    Attached Files Attached Files

  2. #2

    Re: Threading and leaking memory - a demonstration

    You can check out my IM class or my downloader class in my signature as they both involve multi-threading. I have not run into memory issue, but I need to read into your code a bit more...I'm not to sure about some things on it.

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    Thanks,

    Can you provide link info the projects you mentioned? I searched and didn't find them.

    Thanks.

  4. #4

    Re: Threading and leaking memory - a demonstration

    Umm...they're right in my signature:
    File Downloading Class & TCP Client/Server Classes

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    OOPS, saw those but didn't seem like they mapped directly. I'll check it out some more.

  6. #6
    Frenzied Member MaximilianMayrhofer's Avatar
    Join Date
    Aug 2007
    Location
    IM IN YR LOOP
    Posts
    2,001

    Re: Threading and leaking memory - a demonstration

    The problem is a flaw in your code. I was able to reduce memory leakage drastically, essentially remove it, by simply adding the following line to your code:

    Code:
    For u As Integer = 1 To 10000
        Dim x As Integer = 0
        For Each POy As ProcessClass In ThreadCollection
            If Not POy.t Is Nothing Then POy.t.Abort() <-- You have to abort the existing thread, as simply assigning the pointer 't' to a new thread will orphan existing threads that are not completed.
            POy.t = New Thread(AddressOf POy.DoThreadWork)
            POy.t.Start()
        Next
    
        ...
    
    Next
    This is by no means the end all solution, but it's something to start with.

  7. #7

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    That looks right. Thanks for running the sample!

    I thought the threads were supposed to die when they left the scope of their routine but this actually makes more sense as it is instead tied to the scope of the thread variable.

    I won't have time to follow up on this until tomorrow PM. I'll let you know how it goes.

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    Okay. This is not the answer and the problem looks to be much bigger then I first thought.

    The current usage of "disposable" threads, which I thought was more or less how MS had intended it has some really ugly side effects besides just memory leaking.

    First, the Abort does seem to help with the memory issue. There's a lot of jumping around in terms of memory utilization but that's likely attributable the "whenever I happen to get around to it" algorithm of the garbage collector. There may still be a slight accumulation but I haven't gotten that far.

    What I have noticed is that closing the app does not kill the process. This is true both in and out of the debugger. Tried a finalize to specifically kill the threads (thinking their activity was blocking the process kill). No go. If you check the non-debug version in Task Manager, you'll see the app go away but the Process lingers on.

    While threads/processes are always a bit dicey, I do think that the current scheme seems to be well short of ready for prime time. I may need to try Threadpooling even with it's increased overhead. The thought would be that thread reuse may allow for a more stable runtime than constant creation/destruction.

  9. #9
    Frenzied Member MaximilianMayrhofer's Avatar
    Join Date
    Aug 2007
    Location
    IM IN YR LOOP
    Posts
    2,001

    Re: Threading and leaking memory - a demonstration

    It's not closing because you're still orphaning threads when you just close the form after starting your creation loop. Again, in the form closing event, cycle through all of your open process objects and call abort on their threads if they are not nothing. Then your application will close.

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    Do you go by Max?

    I tried that with IDisposable in the RunLoop and the closing event in the form. Neither worked. Any other suggestions?

    Sorry, should have covered that in my previous post.
    Last edited by jbmckim; Aug 10th, 2010 at 09:58 PM.

  11. #11

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    And just as a sort if whining theoretical question, from what I've read of threads wouldn't one expect .NET to clean up after itself? I know that's not real life or we'd all be "Drinkin' that free Bubble Up and eatin' that Rainbow Stew." I'm just thinking that the threading seems to be positioned like that in the .NET framework and it seems a good deal removed from that.

  12. #12

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    Okay,

    Here's something I'd discovered a time ago that dawned on me last night as I was falling asleep.

    YOU CAN'T USE A FOR LOOP (IN VB) FOR THIS SORT OF ACTIVITY. If you use a do or a while with a Public control variable, THEN you use the relevant Form.closing event to set the control variable to done. That exits the loop and allows the app to die.

  13. #13
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Threading and leaking memory - a demonstration

    Making POy.t a background thread would help with your Closing.

    It has always been my understanding that using .Abort is a bad idea. I wish I could see the actual code but I don't download.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  14. #14

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    This version has the .Abort commented out. I was experimenting.

    Here's the class with the sub that hosts the loop:

    Code:
    Imports System.Threading
    
    Public Class RunClass
        Public Done As Boolean = False
        Public ProcessObjectArray(NT_Test.NUM_THREADS) As ProcessClass
        Public ThreadCollection As New Collection
        'Dim t(NT_Test.NUM_THREADS) As Thread
        Dim WithEvents PO As ProcessClass
        Public x As Integer = 0
        Public Shared LockObject As New Object
    
        Public Sub RunIt()
            'Dim t As Thread
            'Dim i As Integer = 0
            'Dim PO As New ProcessClass
    
            'PO.sDisplayText = i.ToString
            't = New Thread(AddressOf xyz)
            't.Start()
    
            Dim Start As Date = Now
    
            ThreadCollection.Clear()
            For i As Integer = 1 To NT_Test.NUM_THREADS
                Dim POx As New ProcessClass
                'Dim POz As New ProcessClass
                POx.sDisplayText = i.ToString
                ThreadCollection.Add(POx, i.ToString)
            Next
    
            Dim u As Integer = 0
    
            While Not Done
    
                Dim x As Integer = 0
                Dim POy As New ProcessClass
                System.Windows.Forms.Application.DoEvents()
                For Each POy In ThreadCollection
                    'PO = POy.Clone
                    'If Not POy.t Is Nothing Then POy.t.Abort()
                    POy.t = New Thread(AddressOf POy.DoThreadWork)
                    POy.t.Start()
                Next
    
                'System.Windows.Forms.Application.DoEvents()
    
    
                Dim POv As New ProcessClass
                'For Each POv In ThreadCollection
                'NT_Test.Label1.Text = POv.sDisplayText
                'Next
    
                For Each POv In ThreadCollection
                    Dim bREallydone As Boolean = True
                    bREallydone = POv.t.IsAlive
                Next
    
                NT_Test.Label1.Text = u.ToString
                System.Windows.Forms.Application.DoEvents()
    
                u = u + 1
                If u = 10000 Then
                    Done = True
                End If
    
            End While
    
            Dim Ending As Date = Now
            Dim Difference As System.TimeSpan = Nothing
    
            Difference = Ending - Start
    
        End Sub
    Agreed .Abort is nice if it can be avoided. The problem seems to be though that .NET does not behave as promised. That is, do what you like and the omniscient garbage collector will clean up after you. When that sort of thing doesn't work as advertised, then "jiggling the wires" unfortunately becomes necessary. I've never gotten through a large project without stumbling over something like this.
    Last edited by jbmckim; Aug 11th, 2010 at 11:16 AM.

  15. #15
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Threading and leaking memory - a demonstration

    This
    Code:
    Public Class Form1
    
        Private Sub Button1_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles Button1.Click
            For x As Integer = 1 To 50
                Dim t As New Threading.Thread(AddressOf foo)
                t.Start()
            Next
        End Sub
    
        Const aSZ As Integer = 1024 * 1024 - 1
        Public Sub foo()
            Dim a(aSZ) As Long
            Do
                Threading.Thread.Sleep(100)
            Loop
        End Sub
    End Class
    type of code will cause errors.

    This is slightly better
    Code:
    Public Class Form1
    
        Private Sub Button1_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles Button1.Click
            For x As Integer = 1 To 50
                Dim t As New Threading.Thread(AddressOf foo)
                t.IsBackground = True
                t.Start()
            Next
        End Sub
    
        Const aSZ As Integer = 1024 * 1024 - 1
        Public Sub foo()
            Dim a(aSZ) As Long
            Do
                Threading.Thread.Sleep(100)
            Loop
        End Sub
    End Class
    and instead of .Abort

    Code:
    Public Class Form1
    
        Private Sub Button1_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles Button1.Click
    
            Dim l As Long = Threading.Interlocked.Exchange(isRun, 1L)
    
            For x As Integer = 1 To 1
                Dim t As New Threading.Thread(AddressOf foo)
                t.IsBackground = True
                t.Start()
            Next
        End Sub
    
        Private isRun As Long = 0
        Const aSZ As Integer = 1024 * 1024 - 1
        Public Sub foo()
            Dim a(aSZ) As Long
            Do
                Threading.Thread.Sleep(100)
            Loop While Threading.Interlocked.Read(isRun) > 0L
            a = Nothing
        End Sub
    
        Private Sub Button2_Click(ByVal sender As System.Object, _
                                  ByVal e As System.EventArgs) Handles Button2.Click
    
            Dim l As Long = Threading.Interlocked.Exchange(isRun, 0L)
    
        End Sub
    End Class
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  16. #16
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Threading and leaking memory - a demonstration

    "That is, do what you like and the omniscient garbage collector will clean up after you." -- I don't think that's ever really been true... It's gotten BETTER (compared to VB6) ... but it's still far from perfect, and still requires a fair amount of due diligence on the developer. In addition, I'd argue that what you are doing is probably not typical of a majority of applications out there, a vast majority of which the GC works "as advertised" and reasonably well.

    I think the problem is that when it comes to threading, some normal rules get thrown out... making memory management a bit more difficult.

    Just my two centavos.

    Is there a reason for using "Collection" instead of List(Of T) or a Dictionary(Of K, T)? I wonder if using a Dictionary and making it private rather than Public would change anything. Just thinking out loud here.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  17. #17

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    I'm going to fiddle with both the ideas in both of these posts.

    My biggest concern here is with memory leaks. Running some endurance tests, it seems that .Abort does make the problem smaller/slower to manifest, but doesn't eliminate it.

    I would think that, while the scale of what I'm doing here might be larger than most, that it would be a fairly typical use of threading. I've used process splitting and threading in tcp/ip apps (c++) a few times in this manner.

    My point in Bill bashing is only to prod past the reflexive responses of "That's how it's supposed to work." It surely is a good design criteria to get rid of all the thread/process paraphernalia. The problem seems to be that some of that stuff is required to manage the stresses that threading (used in anything other than putting up a status bar for a background update) produces.

    So...off to jiggle more wires.

    I'm going to also experiment with thread pooling to see if that mechanism handles this sort of stressing any more elegantly. I will keep any interested soul informed.

  18. #18
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Threading and leaking memory - a demonstration

    Make sure you read this Thread.Abort

    There are a lot of gottcha's.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  19. #19
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Threading and leaking memory - a demonstration

    I wasn't suggesting that the answer was "that's how it's supposed to work" ... my point is that, as is, it is a 90&#37; solution. I'm sorry you fall into that other 10%. I've been caught in that 10% a couple times myself. It's a fact of life sometimes. Personally, I'd much rather see a more aggressive GC, or some way of dealing with it myself. I'd like to be able to do something like this: object.Release .... it would dispose it, mark it for clean up AND release the memory all in one shot.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  20. #20

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    Exactly TG,

    You can never trust email to fully carry the meaning (or to not carry the wrong meaning), so to the extent I came across like I was trying to assign that to your motivation, I apologize. That wasn't intended.

    The "bleeding edge" is where I've had the "opportunity" to spend most of my career. Usually, when you try to talk to 90&#37; of folk about your specific challenge, they respond with any number of 101 level answers on the subject. That's natural, because they project their own experience onto yours. (I actually do this in reverse to the point where I confuse and occasionally frustrate people.) AND multiply all that by the confusion that comes from doing it in writing as opposed to over coffee (or tequila) and it's a wonder anything useful happens at all.

    I will say though that the help on this board is consistently good. I am making progress. The advice given to this point gives good direction. I haven't yet explored List or Dictionary and I do plan to mess with that some as well.

    Finally, your point as regards the desired .Dispose is very good. That would be resource intensive but very desirable for the type of thing I'm dealing with. Let's hope MS is listening...to someone...somewhere.

  21. #21

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    dbasnett: More good info. Suggests that I'll experiment with moving the abort to the thread and having it call it on itself as the last thing it does before losing scope.

    NOTE TO ALL: Running this in the debugger is slower than dirt. However, running the .exe is completely acceptable. This is the greatest delta I've seen to date in terms of debug environment vs. .exe. If you're travelling this path, don't jump to performance conclusions based on debugger performance.

  22. #22
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Threading and leaking memory - a demonstration

    jbm - try the tequila in the coffee....

    As a case in point regarding how importaint it is to call .Dispose... I actually came across documentation in MSDN on a class where it stated that because the object has no Finalize method... it was IMPERATIVE that the developer call the .Displose method, because doing so would allow the class to properly disconnect from the remote server and close properly (it was the SMTPClient class... in order to diconnect, it needs to sent a QUIT command to the SMTP server to close the connection... which only happens in the Dispose event. !!! )

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  23. #23

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    techgnome - thanks for the recipe. If we ever run into each other, I'll have one with you.

    I just wanted to update anyone who's interested with what I've learned thus far...and to me anyway it's pretty interesting.

    Although it seems to be a popular idea, the System.Threading.Thread approach, per:

    Code:
    Public t As Thread
    t = New Thread(AddressOf POy.DoThreadWork)
    t.Start()
    seems to be pretty resource intensive. This makes sense I think because the idea here is that you're building, using and then throwing things away as you go. Even on current cpu's this can get expensive quickly.

    For high volume threading, I'm finding that Thread pooling is extraordinarily faster. However, there's a catch.

    It's so fast, that if you have a large number of threads that iterate repeatedly (think looping through an array - or like - of running threads over and over), it looks like whatever-they-call-the-time-slice-chipper-on-Vista/7, begins to have to queue up entries into the return from the thread. Essentially, you start to create a rush-hour style blockage at the point that the threads are being created/initiated just because the threads themselves are so damn fast.

    I'm currently experimenting with system sleeps in both the mainline and the threads to see how the cpu/memory managers respond. As you can likely tell, I'm not yet understanding what I'm seeing very well but the entire environment is leaking less, using much less cpu AND completing in slightly better elapsed time than was previously the case. (Again, pooling is being used as well, so there's multiple controls in play.)

    For the time being, I'd say pretty certainly that if you have a really intense throughput requirement, you go directly to the threadpool and stay away from dynamic thread creation/destruction.

    I'll post my new code when I understand what it's actually telling me a little better.

  24. #24
    PowerPoster SJWhiteley's Avatar
    Join Date
    Feb 2009
    Location
    South of the Mason-Dixon Line
    Posts
    2,256

    Re: Threading and leaking memory - a demonstration

    I may be missing something, here, but isn't the result of this whole exercise a case of 'you don't get something for nothing'?

    If you are running lots of very short lived tasks, why create a thread for each task? Why not create a single thread and queue those tasks?

    It seems like you are making a shopping list and driving to the store, getting a single item then driving home; getting back in the car to get the next item on the list, driving to the store, and so on. As you normally do, you get all the items in one trip.

    The thread pool, however, is designed to do that: the ability to create threads very quickly on demand. But even that takes resources - that's why servers tend to be multi-processor with a huge dollop of RAM.

    While the 'standard' philosophy is to create and access resources when you need them, if the act of simply creating the resource and it's requirements is expensive, then creating it ahead of time can be beneficial.

    You could create a single thread which accesses a queue of objects to work on. If there's no objects then it sits there, idling in a do/loop or some such. Your main thread (or threads) then put these objects in the queue to be worked on, the worker thread signaling when each item is complete.

    Also, I don't think there is a memory leak as such: yes, memory appears to be consumed, but the framework is not throwing things away because you keep needing the memory very, very quickly. Disposing the objects can be expensive also, so rather than kill the application performance to take a timeout to clean up, it just assigns it more memory.

    In other words, considering a 'shopping list' example, rather than waiting for the first car to come back from the store, a new car is used to get the second item, and another for the third and so on. Since each car can be only used once (it's a thread that has completed), you can either take time out to sell the car or get another car for the next item on the list. To maintain performance (getting items on the list) the junk heap of cars is going to get pretty big before there's time to dispose of them.
    "Ok, my response to that is pending a Google search" - Bucky Katt.
    "There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
    "Before you can 'think outside the box' you need to understand where the box is."

  25. #25
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Threading and leaking memory - a demonstration

    @stephen - slumming I see. Great point.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  26. #26

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    SJ - If I read you correctly, we find ourselves mostly in violent agreement.

    You could create a single thread which accesses a queue of objects to work on.
    Again, if I'm understanding you, I don't think this works in the context of my requirement. I'm reading a number of USB devices. Each device incurs relatively substantial latency (20-100 milliseconds). The point is to incur the collective latency at one time, such that I'm reading 30 devices more or less at once rather than sequentially.

    Or using your example, I have a LOT of groceries to get. I'd rather send 30 cars and drivers to the store at once and get them back home so we can fire up the party sooner.

    Since building a threadpool based testbed (as opposed to the example I originally uploaded), it seems that stripping away the overhead of thread construction/disposal gives a clearer view of how resources are utilized. I think what I'm now seeing is pretty much in line with what you describe. The cpu consumption increases gradually over the life of the run. This is expected in any reasonably tight loop, being run under any conventional sort of instruction queuing scheme. I'm still seeing a good bit of memory loss though. I have however, noticed a correlation between a delay posted (System Sleep) in the Run Class corresponding to a lessening of memory consumption. I'm going to experiment with this some more to see where it leads.

    I don't think its a case of wanting something for nothing. I think it's more about reading the MS documentation (which sometimes is a bit close to marketing literature) and then wanting to understand how MS is managing time division queuing given threading, viz a vi my requirement. I do wish this implementation offered a few more tools for managing this process and maybe inquiring into it at run time. Due to non-technical constraints, I'm bounded to a .NET implementation. I'd have much rather gone with c++ in an unmanaged solution for this sort of thing.

  27. #27
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Threading and leaking memory - a demonstration

    Quote Originally Posted by jbmckim View Post
    SJ - If I read you correctly, we find ourselves mostly in violent agreement.



    Again, if I'm understanding you, I don't think this works in the context of my requirement. I'm reading a number of USB devices. Each device incurs relatively substantial latency (20-100 milliseconds). The point is to incur the collective latency at one time, such that I'm reading 30 devices more or less at once rather than sequentially.

    Or using your example, I have a LOT of groceries to get. I'd rather send 30 cars and drivers to the store at once and get them back home so we can fire up the party sooner.

    Since building a threadpool based testbed (as opposed to the example I originally uploaded), it seems that stripping away the overhead of thread construction/disposal gives a clearer view of how resources are utilized. I think what I'm now seeing is pretty much in line with what you describe. The cpu consumption increases gradually over the life of the run. This is expected in any reasonably tight loop, being run under any conventional sort of instruction queuing scheme. I'm still seeing a good bit of memory loss though. I have however, noticed a correlation between a delay posted (System Sleep) in the Run Class corresponding to a lessening of memory consumption. I'm going to experiment with this some more to see where it leads.

    I don't think its a case of wanting something for nothing. I think it's more about reading the MS documentation (which sometimes is a bit close to marketing literature) and then wanting to understand how MS is managing time division queuing given threading, viz a vi my requirement. I do wish this implementation offered a few more tools for managing this process and maybe inquiring into it at run time. Due to non-technical constraints, I'm bounded to a .NET implementation. I'd have much rather gone with c++ in an unmanaged solution for this sort of thing.
    I guess I missed where you told us this was about reading from USB devices. Why not start permanent threads for each device that reads the data and places the data into a queue that processes it from another thread / UI thread. I did something similar using two USB to serial port adapters. It would help to know much more about your USB devices.
    Last edited by dbasnett; Aug 13th, 2010 at 11:30 AM.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  28. #28
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Threading and leaking memory - a demonstration

    It is my humble opinion that if Bill Gates had been a systems programmer on a large mainframe, with multiple processors and lots of IO devices(multiple strings of disk drives, tape drives, card readers, card punches, line printers, terminals, etc.) before the career we all know of, threading would be a lot easier. Multi-programming / multi-processing are not difficult concepts, though they are less forgiving.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  29. #29

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    @dbasnet -

    I'll answer your 2nd post first: AMEN BROTHER! BITD, this sort of thing was easy on HP and DEC iron and Bill was nowhere to be seen.

    First post: Don't feel bad, you missed the USB part because I didn't include it. I was mainly concerning myself with .NET thread design behavior. Didn't imagine anyone would be interested (and they might even be put off) by such a low level description.

    Essentially though, I'm dealing with an array of broadband optical spectrometers, supporting a mfg process. These are fun little devices with reasonably solid firmware...although I do have to climb down on the eprom from time to time for some quality burn time. The real time requirement is pretty lax, best expressed by something like: "As fast as you possibly can." There are no tick or time coordination requirements.

    The spectrometers have two settings that drastically affect latency. 1) integration time (same thing as length of exposure on your camera) and scans to average (this is a way of smoothing the wave produced by the spectrometer reading). Both are expressed in milliseconds and the two are multiplied by each other to get total et for the measurement. So Integration * Scans To Average = Elapsed time. (You can start to see why I want to thread this - Threading allows me to incur the ET something like simultaneously.)

    The software I'm writing scales to the number of spectrometers the customer wants in place during his mfg process (Vacuum deposition). The usual number is somewhere between 1 and 8...maybe 12 on a huge system. Single threading on a 4 core or better cpu, generally handles these requirements within specification pretty handily. So, naturally, we have someone standing in the door holding a requirement for 72 (each spectrometer will support 2 points of measurement via an optical switch) in one hand and a stinking obscene pile of money in the other hand...we're trying really hard to get them to actually come inside the door.

    Okay, as I said above, the app scales. A database set up at our build time informs the software how many spectrometers it's going to be managing. At run time, the software reads the db and builds a discrete object for each spectrometer. Each spec object manages measurement, display and interface to a separate USB based switch

    Each spec object, is "run" from an external program. This is mimicked by the project file I posted...except for the fact that the spectrometer class/objects contain about 3000 lines of code (I'm not real proud of that).

    Do you have a pattern or know where I can find one for establishing permanent threads in .NET? This wasn't clear to me from the stuff I looked at. The threadpool looked to be closed to this paradigm.

    Thanks & I hope you're not now BOTH blind and bored.

  30. #30
    PowerPoster SJWhiteley's Avatar
    Join Date
    Feb 2009
    Location
    South of the Mason-Dixon Line
    Posts
    2,256

    Re: Threading and leaking memory - a demonstration

    I'd use a single thread per device; if you have 64 devices, that's 64 threads. Add a device, add a thread. Remove a device, remove a thread.

    Essentially, you'll have the thread created when your device is detected and connected (presumably through your high level 'device manager' class). That thread will essentially have a Do/Loop in it managing the device (the thread will be encapsulated in a class, of course).

    Now, I'm not certain of the details about how the data is managed and acquired from the device, but it's possible you may need an additional thread per device; what you will be doing is using a single thread to manage data acquisition as fast as possible, the original device thread treating/massaging the data and presenting it to the manager. I think that's a worst-case scenario, though.

    Essentially, each thread is created once: you won't kill the threads except when the device is removed or the application shuts down.

    The thread pool isn't appropriate for your application, I think. That's designed for something like a web server where the application doesn't know what the requirements may be at any given time. Your app is predictable: you have a given number of devices that exist for the life of the application (give or take).
    "Ok, my response to that is pending a Google search" - Bucky Katt.
    "There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
    "Before you can 'think outside the box' you need to understand where the box is."

  31. #31

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    That would be ideal. Are you aware of any decent patterns for persistent threads in VB? I have a couple books that deal with the pool and Background workers, one that treats different forms of threading but nothing mentions persistent threading.

    The concern I have is that a good many things in VB.NET are meant to disappear when they "go out of scope." If persistent threading is derived from the elements I've seen so far, my concern is that I'll incur unintended deletion and recreation.

    I can of course, build by own "non volatile" thread array/list/collection/etc and create what is essentially a custom threadpool of my own.

  32. #32
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,897

    Re: Threading and leaking memory - a demonstration

    I think I posted an example that would be a place to start.
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  33. #33

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    Okey doke. (I'd forgotten about that previous post.)

  34. #34

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    Quick update on my way to completing this. Folding,spindling and mutilating the example code posted by dbasnett to more closely resemble my multi-class requirement, the memory and cpu stability seem pretty solid thus far. There's a lot of fluctuation but the GC eventually catches up and returns to what looks to be a baseline range. Further, introducing a sleep into the outermost loop seems to drop memory fluctuation to 0 - I suspect the GC is doing it's thing in the time between loops.

    I've got a bit more to investigate, however no questions for now. When done, I'll rate the posts of all and upload my finished test bed in case anyone is REALLY bored and wants to investigate further.

  35. #35

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    P.S. This method is STUPID FAST compared to the others I was experimenting with.

  36. #36

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    Got pulled off for a few days onto something else...sorry for the delay.

    The "Interlock" method above works fairly well but is not determinate. Thread events can execute unexpectedly and occasionally miss an interlock toggle. The degree of leakage corresponds to the number of threads executed. Fewer threads = more leakage. This makes sense if you step back from the PC, go for a walk and think a bit.

    Looked further and I seem to have found what I was originally looking for in the context of my design "challenge." Essentially this is a "Wait" implementation in which threads can be idle until their respective waits are unblocked, AND the main thread is idle until the "server" threads complete. (All the usual disclaimers about coordination/timeouts and deadlocks apply.)

    There's a problem though. Using the code/project below:

    Imports System.Threading
    Public Class Form1
    Public WaitThreadEvents(2) As AutoResetEvent
    <MTAThread()> _
    Sub Main()

    End Sub
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    For i As Integer = 0 To 2
    WaitThreadEvents(i) = New AutoResetEvent(False)
    Next
    WaitHandle.WaitAll(WaitThreadEvents)
    End Sub

    End Class
    WaitHandle throws the exception: WaitAll for multiple handles on a STA thread is not supported.

    I've explicitly declared the MTA Apartment structure, so what's up?

    Thanks.

    PS: Also tried using MTAThreadAttribute with same result.

  37. #37

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    99

    Re: Threading and leaking memory - a demonstration

    After thinking about this overnight, I'm going to start a new thread to hopefully make this a little clearer.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width