1,521 karma · joined May 25, 2012
The new GC is introduced in this comment:
https://github.com/dotnet/runtime/issues/96213#issuecomment-...
In this example i feel like it is treating metrics as the only telemetry signal that operators have access to. Once the metrics indicate an issue, we can pull existing logs, traces and profiles to dig into it and eventually capture dumps.
I'm totally onboard with the idea of rich trace metadata, but it seems more evolutionary than revolutionary
1. Juice up your Traces with every attribute possible 2. Use a telemetry backend that relies on cheap object storage so that your costs don't explode. 3. ...profit?
Ok, but now we are exporting and storing everything about every request just so we can derive some previously cheap metrics like server CPU consumption? I guess for most applications the overhead of buffering, formatting and sending all of this telemetry data doesn't matter for folks?
I had some issues with the Libre 2 sensor getting knocked off or loosening after a few days in the shower. But the libre 3 is smaller than a US quarter coin and lasts 15 days and doesn't snag on anything. Will this watch exceed that? Because if not, then I'm not looking to switch.
Lastly for diabetics or pre-diabetics that are only using finger sticks, I CANNOT stress enough how important a CGM is to your health. You learn so much about how your body actually works with certian foods rather than low frequency (but somewhat more accurate) finger sticks and that information dropped my A1C like a rock in just a few months. Tell your older relatives also. These are life saving devices.
After a while, I found myself adding back types in a decent number of places to "anchor" the type inference, indicating that a certain type/signature is fixed and a change should be carefully considered.
I still don't know how folks deal with these kinds of changes in weakly typed languages without always allowing bugs to pour into their code over time. But I do love the "move fast" and low boiler-plate aspects of "typeless" coding.
Distributed locking, like all pessimistic concurrency, has a place but it comes with serious scaling concerns depending on how granular the scope of the locks are. Lock lived locks suffer from blocking other writers from large chunks of time, destroying latency. Very fine-grained locks eventually become dominated by networking overhead since the lock requires two to three trips to the database for each logical write/update.
Conversely, optimistic concurrency under high contention can lead to excessive waste from clients needing to retry operations because of conflicts.
The only way to win is reduce the scope of your writes/updates to avoid the contention as much as possible.
That being said, you can take proactive steps to defeat this. For example, the default Hash for strings in .NET is randomly seeded each time a process starts[1] in order to strongly dissuade folks from taking an implicit dependency on the underlying algorithm which is not guaranteed to be stable
[0] : https://en.wikipedia.org/wiki/Protocol_ossification
[1] : https://andrewlock.net/why-is-string-gethashcode-different-e...
---EDIT---
Mean to post this under the GP
And line for line, F# is more effective at getting things done (and i would argue with less bugs)
Over the years C# has been implementing these features too, which is good, but they have been implementing them in incompatible ways, which isn't very good. Since the investment in F# has been much smaller than in C#, it hasn't been innovating as fast as C# and has been left behind in some ways.
But it is still a great language and remains broadly compatible with the ecosystem and can deliver equal performance to C# with far less boiler plate
I am not aware of any production grade replacement GCs for .NET out there currently
I forgot that there is built in support for this model using the MemoryManager<T> class [0]. A memory manager is an abstract class that represents a block of other memory, including possibly unmanaged memory. It implements IDisposable already so you can just plug into this.
The Memory<T> struct can optionally internally point to a MemoryManager instance allowing you to plug your perfered style of allocation and freeing of memory into parts of the framework.
There is a little irony that a MemoryManager<T> is itself a class and therefore managed on the gc-heap, but you can defeat this by using ObjectPool<T> to recycle those instances to keep allocation count steady state and not trigger the GC.
I have used this before (in the toy database i mentioned earlier) to allocate aligned blocks of unmanaged memory.
[0] https://learn.microsoft.com/en-us/dotnet/api/system.buffers....
I wish Anders was still in charge of C# :(
Yes and no. Yes, almost all of the standard library collection are allocation heavy and it is still the dominate pattern in C#, so if you want to avoid the GC you need to avoid these and resort to building your own primitives based on Memory/Span. Which sucks.
However, you can use interfaces in a no GC world since you can constrain those interfaces to be structs or ref-structs and the compiler will enforce rules that prevent them from being boxed onto the GC heap.
Also of recent note, the JIT can now automagically convert simple gc-heap allocations into stack allocations if it can trivially prove they don't escape the stack context.
> It would be better if the GC can be turned off with a switch and just add a delete operator to manually free memory.
It is a little know fact that you can actually swap out the GC of the runtime. So you could plug in a null implementation that never collects (at your own peril...)
As for a delete operator, you can just roll your own struct based allocation framework that uses IDisposable to reclaim memory. But then you need to deal with all the traditional bugs like use-after-free and double-free and the like.
For me, I think low-gc is the happy medium. Avoid the heap in 99% of cases but let the GC keep things air tight