1

Here is a image of a profile session of a .NET Framework 4.6.2 WinForms Application that is build on DevExpress XAF and uses XPO as ORM.

I'm faced with a memory leak that seems to be residing in unmanaged memory. In this image you can see that the total memory of our application has risen 2 GB. I've created snapshots before and after the memory increase. But the Visual Studio profiler says that there is only a +/- 45 MB increase. The increase happens when the end user refreshes the screen. Every refresh adds about 100 mb of memory.

enter image description here

How can I properly diagnose the unmanaged memory so I can see what it contains and where it comes from? The current snapshot details are not showing anything that explains the memory difference.

Based on the shown results I am expecting a memory usage of about 800 mb after the second snapshot and not the 2 gb as shown.

We have had cases that the memory usage had risen to 150 gb while profiler sessions only show a marginal memory increase

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
Jacob de Boer
  • 479
  • 6
  • 12
  • 2
    how do you know it is because of unmanaged code? – urlreader Jul 11 '23 at 15:08
  • 1
    Click on the object count to see what objects were actually created. It may well be that inefficient code or forgetting to dispose leaves buffers pinned in memory. Or creates a lot of orphaned objects that need to be garbage-collected. The application was using way too much RAM before this increase so *something* is going wrong – Panagiotis Kanavos Jul 11 '23 at 15:21
  • Adding items to a List<> one by one is inefficient, because a `List<>` stores items in an internal buffer. When it's full, a new one is allocated with double the size and the old one gets GC'd at some point. Adding items one by one results in log2(N) reallocations. Same with a `MemoryStream`. Internally, it's a `byte[]` buffer. With lists and other containers, you should use the `capacity` constructor argument to preallocate the buffer. – Panagiotis Kanavos Jul 11 '23 at 15:24
  • With streams and arrays in general, *reusing* buffers reduces the problem dramatically. [ArrayPool](https://learn.microsoft.com/en-us/dotnet/api/system.buffers.arraypool-1?view=net-7.0) keeps an array of reusable buffers in a pool, removing the need for allocating new ones – Panagiotis Kanavos Jul 11 '23 at 15:25
  • @Panagiotis Kanavos: There's nothing to see in the details that explains the memory difference of about 1200mb – Jacob de Boer Jul 12 '23 at 06:41
  • @urlreader: The image shows a memory usage of 2gb after the second snaphost. The snapshots show a increase of about 45 mb. So I'm guessing that the difference is in unmanaged memory. – Jacob de Boer Jul 12 '23 at 06:56
  • 1
    @JacobdeBoer having investigated a *lot* of such issues in the past, reducing 1GB to 40MB, *oh yes there is*! It's either that, or accepting there's no solution because nobody can see what's going on on your machine. – Panagiotis Kanavos Jul 12 '23 at 07:16
  • 1
    Right now the question contains no information except a significant increase in memory. That's why it was closed. And a debug window that offers to tell you where that memory went, if only you check it. *Process* memory is all the memory used by your application, including garbage that hasn't been collected yet. 300MB RAM is a *lot* already and should be investigated. The window doesn't show any GCs (blue marks) which is itself unusual. Have you done anything to prevent or delay garbage collections? – Panagiotis Kanavos Jul 12 '23 at 07:19
  • 1
    The question doesn't mention what kind of application this is, which affects whether the GC works in server or workstation mode. The runtime version isn't mentioned either. Is this .NET Core? .NET Framework? Which version? If .NET Framework, are there any switches in app.config or web.config that modified the GC behavior? How come there are no garbage collections when so much memory got allocated? – Panagiotis Kanavos Jul 12 '23 at 07:29
  • 1
    More missing information: does the application allocate large buffers? These are allocated on the [Large Object Heap](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/large-object-heap) which is GCd less frequently. That's because large buffers are created infrequently and used for longer. – Panagiotis Kanavos Jul 12 '23 at 07:33
  • 1
    What is the application loading? 100MB for a simple refresh suggests it's loading an entire table or database into memory, even though just 50 rows can be shown in a grid at a time. – Panagiotis Kanavos Jul 12 '23 at 13:52
  • @Panagiotis Kanavos: I have checked the report to see wich objects are created in the meantime and how much space they use. Also I've seen some orphaned objects but they also do not account for the memory increase. The application is a desktop winforms app and there's nothing done to prevent GC from happening. We have disabled as much code as we can that's being executed on a refresh, but nothing helped. The application uses 500 - 750 mb of memory when started. This is caused by the overhead of the DevExpress XAF framework I ques. – Jacob de Boer Jul 12 '23 at 13:57
  • Don't guess. Something's wrong. When XAF was first created, 2GB was the limit for 32-bit computers. Only servers had that much anyway. The overhead may be due to a bad model, code or patterns. If you use SQL Server, use Activity Monitory, Extended Events or the profiler to see what's being loaded. – Panagiotis Kanavos Jul 12 '23 at 14:15
  • A bad model would be one containing all entities, where loading a single entity causes a lot of others to be loaded, whether they're needed or not. Bad code could be a Customer form that also loads all Orders, whether they're shown or not. Or a grid that doesn't use data virtualization or paging, loading everything in memory. I'd suggest starting a *new* clean project with a simple model, simple database, to check how XAF really behaves. – Panagiotis Kanavos Jul 12 '23 at 14:18
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/254465/discussion-between-jacob-de-boer-and-panagiotis-kanavos). – Jacob de Boer Jul 12 '23 at 14:33

0 Answers0