Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. C# Memory Leak Mystery

C# Memory Leak Mystery

Scheduled Pinned Locked Moved C#
csharpperformancehelpquestiondotnet
6 Posts 4 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    Jason Pease
    wrote on last edited by
    #1

    I'm trying to understand how the .NET framework manages memory and I've been using various profiling tools but there are still a few things that don't add up that maybe someone here can help me with. I've been using primarily devPartner studio with a sample project just to test a few things out. Let's start with the simplest of examples. If I create a loop that calls a dummy function that does nothing, something just to occupy memory, after the garbage collector runs a small amount of memory remains occupied. Granted it's only 324 bytes, but it should be 0 bytes and I need to figure out why. DevPartner Studio tells me I have 7 unreachable objects for a total of 208 bytes. My question is that if the garbage collector just ran, why are there any unreachable objects left? The rest of the memory (116 bytes) is occupied by an object array named "String Table" that I presume .NET was using to keep track of the strings I was allocating to consume memory. Seems the string array is no longer needed it would make sense if it were garbage collected, but if .NET wants to keep it around it really not a problem. At least that behavior is explainable. The 208 bytes of unreachable objects is a bigger problem. The problem becomes much more significant when I create an instance of a System.Data.SqlClient.SqlConnection and open it. After opening the connection, closing it, and garbage collection, I'm left with about 185K of memory that couldn't be cleaned up, about 150K of which is unreachable objects. I haven't yet tested the impact of opening multiple connections or repeatedly opening and closing the same connection. Any ideas will be greatly appreciated. Thanks, Jason

    Z G S 3 Replies Last reply
    0
    • J Jason Pease

      I'm trying to understand how the .NET framework manages memory and I've been using various profiling tools but there are still a few things that don't add up that maybe someone here can help me with. I've been using primarily devPartner studio with a sample project just to test a few things out. Let's start with the simplest of examples. If I create a loop that calls a dummy function that does nothing, something just to occupy memory, after the garbage collector runs a small amount of memory remains occupied. Granted it's only 324 bytes, but it should be 0 bytes and I need to figure out why. DevPartner Studio tells me I have 7 unreachable objects for a total of 208 bytes. My question is that if the garbage collector just ran, why are there any unreachable objects left? The rest of the memory (116 bytes) is occupied by an object array named "String Table" that I presume .NET was using to keep track of the strings I was allocating to consume memory. Seems the string array is no longer needed it would make sense if it were garbage collected, but if .NET wants to keep it around it really not a problem. At least that behavior is explainable. The 208 bytes of unreachable objects is a bigger problem. The problem becomes much more significant when I create an instance of a System.Data.SqlClient.SqlConnection and open it. After opening the connection, closing it, and garbage collection, I'm left with about 185K of memory that couldn't be cleaned up, about 150K of which is unreachable objects. I haven't yet tested the impact of opening multiple connections or repeatedly opening and closing the same connection. Any ideas will be greatly appreciated. Thanks, Jason

      Z Offline
      Z Offline
      Zdeslav Vojkovic
      wrote on last edited by
      #2

      one of the possible reasons is objects that need explicit finalization (have defined finalizers). when they are not reachable anymore and GC runs, memory for these object is not reclaimed immediately. instead, objects are moved to the so called 'FReachable' queue and their finalizers ar run. the memory is reclaimed in the next GC round. you can find more details here[^] or here[^]

      1 Reply Last reply
      0
      • J Jason Pease

        I'm trying to understand how the .NET framework manages memory and I've been using various profiling tools but there are still a few things that don't add up that maybe someone here can help me with. I've been using primarily devPartner studio with a sample project just to test a few things out. Let's start with the simplest of examples. If I create a loop that calls a dummy function that does nothing, something just to occupy memory, after the garbage collector runs a small amount of memory remains occupied. Granted it's only 324 bytes, but it should be 0 bytes and I need to figure out why. DevPartner Studio tells me I have 7 unreachable objects for a total of 208 bytes. My question is that if the garbage collector just ran, why are there any unreachable objects left? The rest of the memory (116 bytes) is occupied by an object array named "String Table" that I presume .NET was using to keep track of the strings I was allocating to consume memory. Seems the string array is no longer needed it would make sense if it were garbage collected, but if .NET wants to keep it around it really not a problem. At least that behavior is explainable. The 208 bytes of unreachable objects is a bigger problem. The problem becomes much more significant when I create an instance of a System.Data.SqlClient.SqlConnection and open it. After opening the connection, closing it, and garbage collection, I'm left with about 185K of memory that couldn't be cleaned up, about 150K of which is unreachable objects. I haven't yet tested the impact of opening multiple connections or repeatedly opening and closing the same connection. Any ideas will be greatly appreciated. Thanks, Jason

        G Offline
        G Offline
        Guffa
        wrote on last edited by
        #3

        When you close a database connection, the connection itself is not destroyed, but kept in the connection pool. This greatly improves the speed of each following connection to the same database. --- b { font-weight: normal; }

        1 Reply Last reply
        0
        • J Jason Pease

          I'm trying to understand how the .NET framework manages memory and I've been using various profiling tools but there are still a few things that don't add up that maybe someone here can help me with. I've been using primarily devPartner studio with a sample project just to test a few things out. Let's start with the simplest of examples. If I create a loop that calls a dummy function that does nothing, something just to occupy memory, after the garbage collector runs a small amount of memory remains occupied. Granted it's only 324 bytes, but it should be 0 bytes and I need to figure out why. DevPartner Studio tells me I have 7 unreachable objects for a total of 208 bytes. My question is that if the garbage collector just ran, why are there any unreachable objects left? The rest of the memory (116 bytes) is occupied by an object array named "String Table" that I presume .NET was using to keep track of the strings I was allocating to consume memory. Seems the string array is no longer needed it would make sense if it were garbage collected, but if .NET wants to keep it around it really not a problem. At least that behavior is explainable. The 208 bytes of unreachable objects is a bigger problem. The problem becomes much more significant when I create an instance of a System.Data.SqlClient.SqlConnection and open it. After opening the connection, closing it, and garbage collection, I'm left with about 185K of memory that couldn't be cleaned up, about 150K of which is unreachable objects. I haven't yet tested the impact of opening multiple connections or repeatedly opening and closing the same connection. Any ideas will be greatly appreciated. Thanks, Jason

          S Offline
          S Offline
          S Senthil Kumar
          wrote on last edited by
          #4

          First off, how did you make the GC run? GC.Collect? That's not enough. You need to do

          GC.Collect();
          GC.WaitForPendingFinalizers();
          GC.Collect();

          Jason Pease wrote: If I create a loop that calls a dummy function that does nothing That's because the JIT compiler generates native code the first time a function is called and that code obviously takes up some space. If you'd noticed it carefully, you'd have seen that memory consumption doesn't keep rising, it just stays at that point. Nothing short of shutting down the process will reclaim that memory for you. Jason Pease wrote: The problem becomes much more significant when I create an instance of a System.Data.SqlClient.SqlConnection and open it. After opening the connection, closing it, IIRC, the underlying connection is not closed and the managed SqlConnection object is simply pooled, so obviously it can't be garbage collected. Jason Pease wrote: I'm left with about 185K of memory How did you measure? Task Manager? You should be using Perfmon with "#Bytes in All Heaps" counter to get an accurate picture of the size of the GC heap. Regards Senthil _____________________________ My Blog | My Articles | WinMacro

          J 1 Reply Last reply
          0
          • S S Senthil Kumar

            First off, how did you make the GC run? GC.Collect? That's not enough. You need to do

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            Jason Pease wrote: If I create a loop that calls a dummy function that does nothing That's because the JIT compiler generates native code the first time a function is called and that code obviously takes up some space. If you'd noticed it carefully, you'd have seen that memory consumption doesn't keep rising, it just stays at that point. Nothing short of shutting down the process will reclaim that memory for you. Jason Pease wrote: The problem becomes much more significant when I create an instance of a System.Data.SqlClient.SqlConnection and open it. After opening the connection, closing it, IIRC, the underlying connection is not closed and the managed SqlConnection object is simply pooled, so obviously it can't be garbage collected. Jason Pease wrote: I'm left with about 185K of memory How did you measure? Task Manager? You should be using Perfmon with "#Bytes in All Heaps" counter to get an accurate picture of the size of the GC heap. Regards Senthil _____________________________ My Blog | My Articles | WinMacro

            J Offline
            J Offline
            Jason Pease
            wrote on last edited by
            #5

            S. Senthil Kumar wrote: IIRC, the underlying connection is not closed and the managed SqlConnection Maybe it's because my profiler (devPartner Studio) doesn't allow me to see it, but this space only shows up as "Unreachable Objects"; it doesn't show me the type of object. I would have expected to see a pooled connection with some type of indicative name, not Unreachable Objects. This brings up the question though of where a pooled connection is kept. Seems I can utilize the same pooled connection from two different applications (right?), I would have expected it to not be included in the memory of my application space, but instead somewhere else. Maybe I need to study this more thoroughly. S. Senthil Kumar wrote: How did you measure? Task Manager? DevPartner tells me how much memory it is profiling. I've verified this number with the .NET counters and it seems to be reliable. Thanks for your help, Jason.

            S 1 Reply Last reply
            0
            • J Jason Pease

              S. Senthil Kumar wrote: IIRC, the underlying connection is not closed and the managed SqlConnection Maybe it's because my profiler (devPartner Studio) doesn't allow me to see it, but this space only shows up as "Unreachable Objects"; it doesn't show me the type of object. I would have expected to see a pooled connection with some type of indicative name, not Unreachable Objects. This brings up the question though of where a pooled connection is kept. Seems I can utilize the same pooled connection from two different applications (right?), I would have expected it to not be included in the memory of my application space, but instead somewhere else. Maybe I need to study this more thoroughly. S. Senthil Kumar wrote: How did you measure? Task Manager? DevPartner tells me how much memory it is profiling. I've verified this number with the .NET counters and it seems to be reliable. Thanks for your help, Jason.

              S Offline
              S Offline
              S Senthil Kumar
              wrote on last edited by
              #6

              Jason Pease wrote: Seems I can utilize the same pooled connection from two different applications (right?) Really? I may be wrong, but I don't think that's possible. At best, they might be shared across all AppDomains in the same CLR instance. This[^] is a very good (and free) profiler that shows the actual objects in the GC heap. Regards Senthil _____________________________ My Blog | My Articles | WinMacro

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • World
              • Users
              • Groups