1

I have an application which works something like this in pseudocode:

DisplayPrettyUI()
DoABunchOfReportingWorkThatAllocatesHundredsOfMB()
GC.Collect() //Free up the memory used in generating the report
DisplayReport()

Now, I can't get rid of the collect call outright, because if I do that the process holds on to more than a GB of memory after the report is generated, despite the app hosting only the UI components to display the report at that time. At the same time, the call to Collect seems "smelly"; and it seems like there has to be some way of handling this case without going there.

Is removing this smell possible? (I've heard references to things like AppDomain for solving this, but I've never used AppDomain before and don't really know what semantics it has for the garbage collector...)

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • 4
    To this sounds like a legitimate use of `GC.Collect`. – CodesInChaos Jul 29 '12 at 18:07
  • @CodesInChaos: In some respects yes; but it seems like this could be made a lot more efficient. I as the app developer know that this entire set of hundreds of thousands of objects can immediately die; no collection analysis required. I'd be surprised if there was not some allowance for this kind of pattern in the CLR somewhere. – Billy ONeal Jul 29 '12 at 18:08
  • 1
    Try to optimize DoABunchOfReportingWorkThatAllocatesHundredsOfMB() as much as possible obviously but other than that there's not a lot of other options – ghostbust555 Jul 29 '12 at 18:09
  • Try nulling variables when they are useless. It helps in some scenarios. – EOG Jul 29 '12 at 18:10
  • 1
    @EOG: That doesn't make any sense. There are no references into the reporting infrastructure's data from the UI. The garbage collector isn't running because this machine has 12GB of RAM, and as such it doesn't think there's enough memory pressure yet to run. Nulling variables would be worse than useless. – Billy ONeal Jul 29 '12 at 18:12
  • 1
    If the machine has 12GB of memory and has no pressure to free memory then why do you feel you need to manually run GC? – paparazzo Jul 29 '12 at 18:23
  • 1
    @Blam: Because it looks bad when the app just showing the report is holding on to gigabytes of memory. That memory would be better off returned to the OS; so that it can use it for things like disk cache. – Billy ONeal Jul 29 '12 at 18:24
  • 1
    Have you tested how long this memory is being held without the manual GC? Are you having specific performance problems? If you are having performance issues and want more direct control over memory then consider unmanaged c/c++. – paparazzo Jul 29 '12 at 18:53
  • @Blam: 1. Yes, the application is holding on to too much memory. That is a performance problem. 2. It's "native" C++ -- characterizing something by something it isn't makes no sense. Plus C++ doesn't ever run on the CLR so I don't see the point here. (C++/CLI runs on the CLR, but that's a very different language) 3. Rewriting the application is kinda drastic for this sort of thing. – Billy ONeal Jul 29 '12 at 18:56
  • 2
    Easy dude. You don't quantify the performance issues so how can I know if a rewrite is kinda drastic? – paparazzo Jul 29 '12 at 19:51
  • I agree that this is a legitimate use of `GC.Collect()`. As nice as it would be to have a way to manually control memory allocation in .NET, no such thing exists. If seeing the call really bothers you that much, wrap it in a method so that you can do something like this: `MemoryManager.ExecuteAndCollect(() => { DoReportingWork(); });` – Cole Campbell Jul 30 '12 at 18:42
  • It might help a little to call `GC.Collect()` _before_ `DoABunchOfReportingWorkThatAllocatesHundredsOfMB()`. Calling it to improve the memory graph in TaskManager is nonsense. – H H Aug 09 '12 at 00:37
  • @Henk: I don't see how it's nonsense. That's memory being held on to by the application, which does not need to be held on to any longer. That would be better off returned to the OS, so that the OS can use it as disk cache if nothing else. – Billy ONeal Aug 09 '12 at 01:23

2 Answers2

2

You could call GC.Collection with the GCColletionMode flag of Optimized so it isn't necessarily forcing a Garbage Collection at that point....the GC can delay it if it's not necessary.

Also look at the AddMemoryPressure, there's some ideas here:

Colin Smith
  • 12,375
  • 4
  • 39
  • 47
1

The way that we usually address this is to spin off the reports into either separate threads or even physical processes, depending on the tool that we are using.

There are some third-party reporting tools that are absolute resource hogs and have a tendency to bring down the entire application when they crash. Spinning them off into their own processes isolates the potential damage and allows us to instantiate just enough to keep us under our resource limits, but still be responsive to user requests.

Having said that, if this is not an appropriate fit for your application, I don't see anything wrong with using Collect in your circumstance.

competent_tech
  • 44,465
  • 11
  • 90
  • 113