Please forgive me ignorance, but why can't I manually delete an object? Lots of times I know this one object is pretty big and want to delete it when I am done with it, but have to force the GC to run to clean it up.
I'm assuming you're trying to allocate a large array, since otherwise it's pretty difficult to have a large object in .NET.
One thing you can do is use Marshal.AllocHGlobal (this is essentially an unsafe malloc) which gives you a pointer (not reference) to a chunk of unmanaged memory, which you can access with unsafe pointer. This is pretty messy.
The other, more modern thing is using MemoryPool<T>, which gives you a manually managed "array" (Span, .NET-s version of slice) of structs of type T, which you can manually release after you're done with them.
The third option, is just allocate it using new and abandon all references, the create a different copy. The memory pressure of allocating a big object, will probably trigger a GC. This is dangerous, since there can still be dangling references to the old object (that might not even present in the source, but compiler generated), leading you to retain both the old and new memory.
Because they're memory objects that are managed by .Net.
If you said "Hey, I'm done with this" that's great, but .Net can't actually delete it until it's checked for itself that nothing else is using it. Otherwise you'll inject an error into the memory manager when you delete an object that's still in use.
So you can kinda fake a delete by releasing the last reference to an object and then forcing a garbage collection (in .Net I think you can call gc.collect() or something)(it's worth noting that the .Net docs specifically said that .Net might ignore your request to do a gc so even calling that is more of a suggestion than a guaranteed garbage collection)
But gc.collect is quite expensive. I think the parent question was, I have a large object in memory, I want to delete it now so that I can load another large object without running into memory limits. But I don't want to call gc.collect which will stop my whole application, interfer with the garbage collector heuristics, and do all sort of unecessay steps.
I had instances where I knew only one of these large structures could fit in memory and had to call gc.collect before allocating a new one, as I would get an outofmemory exception before the garbage collector would kick in by itself.
You can do that with unmanaged objects but it doesn't look like you can with managed objects (other than gc.collect which I saw on other videos is not recommended by microsoft).
In extreme cases you might be able to emulate arena allocation by spawning an external process, create huge object, do some work on it, throw away the process. How viable this is depends on the programming language you are using. In erlang it can work great, because gc is per process (no shared memory) and you can use green-threads; in languages with very grummy GC like python it can also be worth considering[1] even with the cost of spawning a system process. I haven't kept up to date with Net, but my guess would be it's generally not a very attractive strategy.
[1] Refcounting will be instantaneous of course, but if you have a large heap with a lot of objects and GC kicks in you can have very long gc pauses (even if next to nothing will be reclaimed).
A generational GC as the one in .NET allocates memory up-front, then passes out references/pointers from that allready allocated memory.
When the GC is getting close to the end of the pre-allocated memory, it will analyse all living objects (the objects it can reach from the stack and global variables, and objects referenced by those objects) and copies them over to a different area of memory (generation).
The area the memory was copied from, is now all garbage, and can be overwritten by new objects.
I guess you could say that instead of collecting garbage, it de-fragments your living objects.
If the GC still doesn’t have enough memory, it will try to allocate more.
In any case. The cost of a generational garbage collector is associated with living objects, not dead ones, so manually deleting doesn’t make sense.
No I had instances where I deleted an object, wanted to allocate a new one, only one of these would fit in memory, and got an outofmemory exception because the GC didn't kick in between the two. So it is not equivalent.
torginus|5 years ago
I'm assuming you're trying to allocate a large array, since otherwise it's pretty difficult to have a large object in .NET.
One thing you can do is use Marshal.AllocHGlobal (this is essentially an unsafe malloc) which gives you a pointer (not reference) to a chunk of unmanaged memory, which you can access with unsafe pointer. This is pretty messy.
The other, more modern thing is using MemoryPool<T>, which gives you a manually managed "array" (Span, .NET-s version of slice) of structs of type T, which you can manually release after you're done with them.
The third option, is just allocate it using new and abandon all references, the create a different copy. The memory pressure of allocating a big object, will probably trigger a GC. This is dangerous, since there can still be dangling references to the old object (that might not even present in the source, but compiler generated), leading you to retain both the old and new memory.
MikeTheGreat|5 years ago
If you said "Hey, I'm done with this" that's great, but .Net can't actually delete it until it's checked for itself that nothing else is using it. Otherwise you'll inject an error into the memory manager when you delete an object that's still in use.
So you can kinda fake a delete by releasing the last reference to an object and then forcing a garbage collection (in .Net I think you can call gc.collect() or something)(it's worth noting that the .Net docs specifically said that .Net might ignore your request to do a gc so even calling that is more of a suggestion than a guaranteed garbage collection)
cm2187|5 years ago
I had instances where I knew only one of these large structures could fit in memory and had to call gc.collect before allocating a new one, as I would get an outofmemory exception before the garbage collector would kick in by itself.
You can do that with unmanaged objects but it doesn't look like you can with managed objects (other than gc.collect which I saw on other videos is not recommended by microsoft).
patrec|5 years ago
[1] Refcounting will be instantaneous of course, but if you have a large heap with a lot of objects and GC kicks in you can have very long gc pauses (even if next to nothing will be reclaimed).
Skinney|5 years ago
You only pay a price for living things (as in, some object holding a reference to it), the rest is free.
Skinney|5 years ago
A generational GC as the one in .NET allocates memory up-front, then passes out references/pointers from that allready allocated memory.
When the GC is getting close to the end of the pre-allocated memory, it will analyse all living objects (the objects it can reach from the stack and global variables, and objects referenced by those objects) and copies them over to a different area of memory (generation).
The area the memory was copied from, is now all garbage, and can be overwritten by new objects.
I guess you could say that instead of collecting garbage, it de-fragments your living objects.
If the GC still doesn’t have enough memory, it will try to allocate more.
In any case. The cost of a generational garbage collector is associated with living objects, not dead ones, so manually deleting doesn’t make sense.
cm2187|5 years ago
pjmlp|5 years ago
Then you can allocate and deallocate at will.
Or just use a struct.
kevingadd|5 years ago
jayd16|5 years ago