Writing Allocation Free Code in C# - Matt Ellis

  Рет қаралды 71,339

NDC Conferences

NDC Conferences

Күн бұрын

Пікірлер: 105
@AnitShrestha
@AnitShrestha 5 жыл бұрын
I really like the presentation where Matt covers the basics of CS such as boxing, reference and value types in relation to memory allocation to explain the performance issues is simple yet insightful. Thank you.
@HenrikRClausen
@HenrikRClausen 5 жыл бұрын
I applied this to my code today - and got a performance gain that looks like an order of magnitude!
@osten222312
@osten222312 5 жыл бұрын
Finally someone brings it up! This is important for gamedev since gc introduces stutter where you always want a smooth framerate. The thing I miss most is Linq
@sacredgeometry
@sacredgeometry 5 жыл бұрын
Or you know just allocate ahead of time and just reuse objects with different configurations instead of deallocating them.
@sealsharp
@sealsharp 8 ай бұрын
34:12 Defensive copy on method calls: At the time of this talk ( June 2019 ) the feature called "readonly members" did not exist yet. It premiered in C#8 in September 2019. Readonly members allow to mark methods and property getters on structs as readonly and the compiler enforces that these methods do not change the internal state of the struct. Accessing readonly members avoid the defensive copy on structs that are not as a whole readonly.
@vkg.codefactory
@vkg.codefactory 3 жыл бұрын
Wow, such a great presentation with lots of advanced concepts, thank you for all this Matt, appreciate it!!!
@galandilvogler8577
@galandilvogler8577 5 жыл бұрын
Very useful talk, got some "gotcha moments" out of it even though I studied all the new features from C#7 on. I'd like to correct not a mistake, but a not so great choice of words made in the video, at around minute 10:00 - the default passing of variables to methods is always by *value*, be them ref or value types. In the specific case of value passing a reference type variable, the value that is passed (thus copied) into the local scope parameter is the reference itself, and that ofc means that, even though the original argument and the local parameter are different (since the local param is a copy of the original argument), they both point to the same object in the heap. And this brings the fact that local changes to the data contained in the referenced object are reflected outside the local scope. Just wanted to point this out, cause it can cause some confusion. ;)
@phobos2077_
@phobos2077_ 5 жыл бұрын
C# slowly turns into C++.. the better part of it :)
@FaithfulGeneral
@FaithfulGeneral 5 жыл бұрын
haha never will it ever. ;)
@DEBBAH1907
@DEBBAH1907 3 жыл бұрын
C# now in 2021 is like a mix of C++ python and javascript sadly
@davidklempfner826
@davidklempfner826 3 жыл бұрын
@8:50 This doesn't only happen with boxed value types. Boxed or not boxed, any value type you pass in to a method that mutates that value, the changes won't be observed outside the method (unless you used out/ref). @9:45 I think it should be made more clear that value types are allocated on the stack, or the heap. I know it says in small writing "or embedded into a reference object", but the misconception that "value types go on the stack" is too common, and this kind of adds to it by having the second explanation in smaller writing. @18:38 reference and value types are both cheap to allocate. It's the DEallocating that is expensive for reference types, and involves GC.
@FastFSharp
@FastFSharp 3 жыл бұрын
Fantastic talk! This is exactly the kind of content I have been searching for!
@sken1301
@sken1301 3 жыл бұрын
Is there any tool or option in Visual Studio that can produce the warning of delegate allocation, like the warning "Delegate allocation: capture of 'name' parameter" in the slide at 12:54?
@kobby2g8
@kobby2g8 5 жыл бұрын
A bit off topic, but compiler enforced readonly reference types . I realise it might be a bit of a pain because of inheritance. But it would be really nice to have.
@StephenJWalter
@StephenJWalter 5 жыл бұрын
Excellent presentation.
@lollo4711
@lollo4711 2 жыл бұрын
Cool!!!! TNX! - I will make use of it - although my program´s performance gaps are most times I/O-related. But I like this ref/in/out - and Span will replace string in all bigger string-operations. For POCOs I will still use strings. It´s such a pity that Span implements NO Changed-Event. (A quick intro into GC... where it lives, runs, gets started, if it still runs for clean-up while Main-App has already been terminated... could be very useful)
@wim1983
@wim1983 5 жыл бұрын
hmm, I'm definitely agree on reuse of same object instead of new initialization allocation, just notice System.Text.Json is only available in .NET Core 3? Between not sure how is this useful to few things like List where I need to do data manipulation a lot when come to relational parent child model, and StringBuilder to enhance with Span? Not sure IDBConnection can be pass by ref to reduce allocation?
@samuelgrahame3617
@samuelgrahame3617 5 жыл бұрын
Idbconnection is a class so no point using ref. As it is a reference type. It does that by default.
@wim1983
@wim1983 5 жыл бұрын
@@samuelgrahame3617 I think so.
@logank.70
@logank.70 5 жыл бұрын
This was commented on by another user but it really needs to be repeated. In C# parameters are passed in by value by default. Reference objects are NOT passed by reference. For reference objects the value just happens to be the reference. Two different places in memory that reference the same place the object is at. If you want something passed by reference you have to use the "ref" keyword.
@7th_CAV_Trooper
@7th_CAV_Trooper 3 жыл бұрын
I want a Span that works with files and memory mapped files.
@Grimlock1979
@Grimlock1979 5 жыл бұрын
10:05 No! I hate it when they say "reference types are passed by reference". It's a wrong thing to say. Other languages like Java have reference types, but Java knows pass-by-value only. They are 2 different concepts. The whole point is to pass value types by reference to avoid making copies. (which he later explains correctly)
@PatrickKellyLoneCoder
@PatrickKellyLoneCoder 5 жыл бұрын
Context my dude. He's clearly talking about .NET world specifically.
@Grimlock1979
@Grimlock1979 5 жыл бұрын
Context is irrelevant. "reference types are passed by reference" is a wrong thing to say. But I hear it all the time.
@DavidTimovski
@DavidTimovski 4 жыл бұрын
@@PatrickKellyLoneCoder Pass by reference means the same in the .NET world as any other. The default way of passing is by value, both for value types and reference types. Pass by reference in "the .NET world" is done with the ref and out keywords. Everything else is pass by value, regardless of type.
@DavidTimovski
@DavidTimovski 4 жыл бұрын
@@ghevisartor6005 It does exhibit different behaviour: davidtimovski.com/Blog/12/value-vs-reference-types-not-quite-common-knowledge But I haven't ever in my career had use in it. Frankly if you find that you do need to pass an object using ref/out maybe you were doing something else wrong that led you to it :) I'm open to being educated if there are devs who can come up with a good reason to do it.
@caioavidal
@caioavidal 4 жыл бұрын
Very useful knowledge
@wim1983
@wim1983 5 жыл бұрын
I cannot start to imagine to rewrite all the linq expression to foreach and if...
@balazsarva1991
@balazsarva1991 5 жыл бұрын
You don't need to. While there are some practices for better performance which can be used generally, do keep in mind that performance optimization inevitably comes at the cost of harder maintainability and worse readability. That is because all the nice stuff like linq are high-level abstractions and like all abstractions, they add some overhead. Unless you write some performance-critical code in C#, you wouldn't need to worry about replacing your fancy linq expressions with more low-level counterparts because in 99.999% of the cases, you cannot afford the added complexity which would be caused by doing so. If you are just a typical business system developer, you should favor readability and maintainability over micro-optimization.
@wim1983
@wim1983 5 жыл бұрын
@@balazsarva1991 Actually it's fine, since I'm writing an SQL builder, definitely more code if change all the linq code to foreach, most probably it won't matter much since I'm looping few properties mostly, anyway the class library is serve as middleware, so I think I'm only the one who maintain it.
@wudewang9947
@wudewang9947 5 жыл бұрын
Great explanation.
@bultvidxxxix9973
@bultvidxxxix9973 5 жыл бұрын
1:24 do I hear applause?
@PankajNikam
@PankajNikam 5 жыл бұрын
Must be another conference going on right beside the one that we are watching in this video.
@blakersquakers
@blakersquakers 5 жыл бұрын
Always be measuring was a hit with the crowd!
@LuigiTrabacchin
@LuigiTrabacchin 4 жыл бұрын
thumb up for the initial DON'T and measure it
@LuigiTrabacchin
@LuigiTrabacchin 4 жыл бұрын
and i obviously did not listen to the advice, I've refactored entirely a project (a very rudimental 3D engine) just to give it a try and see what happens... turns out nothing happened, it was just harder to write and understand 😂 But i really wanted to give it a go
@loam
@loam 5 жыл бұрын
But if I use keyword Using when creating an object, so that object is destroyed outside of the scope of that using, is it still ineffective memory usage? Or in such a case: implement IDisposable and call Dispose() method whenever I no longer need an object? Perhaps, in Dispose() method I would be assigning null to the object, so that the object variable now will point at something like 0x000.. , but what will happen to that heap chunk of memory, that stored that object's data?
@balazsarva1991
@balazsarva1991 5 жыл бұрын
"But if I use keyword Using when creating an object, so that object is destroyed outside of the scope of that using, is it still ineffective memory usage? Or in such a case: implement IDisposable and call Dispose() method whenever I no longer need an object?" Wrapping an object in an using block has nothing to do with destroying an object. In C#, only value types are destoryed deterministically and that happens when they go out of scope. Reference types are indeterministically destroyed and when that happens is up to the GC. In fact, there is some level of correlation between some objects being destoryed and an using block but that applies to native resources being wrapped by an IDisposable which the using block disposes at the end of the scope. This is because a disposable object typically wraps - often through a long chain of inheritance - a native resource which the GC is not responsible for handling. And while this applies in the majority of cases, this still does not actually guarantee anything. For example, there is a more-or-less well-known issue with the HttpClient that even when it is explicitly disposed, the underlying socket - a native resource - (at least on Windows) remains open for some time afterwards, possibly causing the so-called socket exhaustion issue. It is a great example for why you shouldn't make any assumptions as to when and how something is destroyed, even about the underlying native resources. Using the "using" keyword and implementing the IDisposable interface is therefore not about managing managed resources and memory occupied by them. It is about giving you the option to explicitly release the underlying native resources as soon as possible since the GC won't do that for you. Even if you explicitly assign null to some field within the object you are not destroying it, you are just removing a reference to it. It will continue to reside on the heap and occupy memory until the GC removes it.
@XTK001
@XTK001 5 жыл бұрын
Dispose() has nothing to do with GC. You dispose an object to release resources that it depends on, but the object itself still lives in memory (and you can call method on it!!). GC is the process of cleaning that object up, which will still happen once the object goes out of scope, whether you called Dispose() on it or not.
@samuelgrahame3617
@samuelgrahame3617 5 жыл бұрын
@@XTK001 also it is used for releasing non manages objects as they are not collected by gc.
@Tyrrrz
@Tyrrrz 5 жыл бұрын
The most effective memory usage is when you don't use memory. Anything departing from that is less effective. If you allocate an object and release the memory afterwards, does it mean that the memory usage is ineffective? No one can tell because it depends on the context. If you allocate and release memory 1000 times a second in a tight loop, it's most likely ineffective memory usage due to interrupts and memory fragmentation.
@Beni9819
@Beni9819 5 жыл бұрын
Which UI is this?
@swstein
@swstein 5 жыл бұрын
Jetbrains Rider. It's great.
@luiscantero
@luiscantero 4 жыл бұрын
Jetbrains Rider
@ComposerJoakimS
@ComposerJoakimS 5 жыл бұрын
The task of the programer should be to express herself as clearly in code as possible. The task of the compiler is to convert that expression into as efficient machine code as possible, given the particular hardware at use. Code that try to second guess what optimisations the compiler is missing will get old very quickly - both because it is not as understandable and maintainable as it could be, and because those flaws in the compiler will eventually be fixed, turning a good optimisation into a bad one, or a useless one at best.
@MobilTemp
@MobilTemp 4 жыл бұрын
What? Herself?
@ComposerJoakimS
@ComposerJoakimS Жыл бұрын
@Melon Husk I really didn't intend to get into the gender debate here. As a non-native English speaker, help me: What is the proper word to put in that sentence instead of 'herself'? I thought herself and himself were interchangable where gender is undefined and not important?
@7th_CAV_Trooper
@7th_CAV_Trooper 10 ай бұрын
​@@VectorTwelve good point, there are only two famous female programmers.
@7th_CAV_Trooper
@7th_CAV_Trooper 10 ай бұрын
​@@MobilTempit's not the compiler's job to efficiently allocate memory. It can optimize your bad idea, for you, but this won't make your bad idea a good idea.
@ivandrofly
@ivandrofly 5 жыл бұрын
Good stuff!
@sergekg2kg844
@sergekg2kg844 5 жыл бұрын
Perfect talk related to C# performance. Now C# and C++ equal in performance using these techniques.
@RandomGuy-we2mn
@RandomGuy-we2mn 5 жыл бұрын
Isn't c# faster?
@bangonkali
@bangonkali 5 жыл бұрын
@@RandomGuy-we2mn i dont think there will ever come a time that C# can beat C++ even with highly optimized codes. But it's always nicer to code in C# than in C++. C++ does have more and more features and IDE's are getting better, so maybe soon C++ 2050 will be just as nice to write with. 😂😂😂
@Adolf1Extra
@Adolf1Extra 5 жыл бұрын
Using both I can tell you that both modern C++ and modern C# are an absolute treat to work with. C++ makes it waaaay easier to write code with better performance characteristics obviously. Get your heads out of your asses and look at current situation of the languages.
@serges467
@serges467 5 жыл бұрын
@@bangonkali Performance for entire application - not just 2*2 or optimized FFT module. C/C++ modules you can call from C#, but in C++ you can't write so elegant code like in C#.
@RandomGuy-we2mn
@RandomGuy-we2mn 5 жыл бұрын
@@bangonkali I was joking about speed :)
@ivandrofly
@ivandrofly 5 жыл бұрын
Very concise!
@anon_y_mousse
@anon_y_mousse 2 жыл бұрын
All of the issues highlighted are why a language should be designed from the ground up to handle all of these things. Instead, they copied Java, which was highly constrained and foolishly so, and extended it with incompatible features from C++, and have had to continuously extend the language to add features that are hacked on to keep up with where developers want to go. So now, we have hot garbage on toast for pretty much every language, because of course, Java, C++ and many more have hacked on kludges to try and keep up. Not that I'm saying a new language should be designed and built every few years to keep up, but maybe we shouldn't try to keep up at all. C is still perfectly fine as a language, it just doesn't have syntactic sugar to handle everything, but it also doesn't have *huge quantities* of gotchas that make programming anything complex a minefield.
@zariumsheridan3488
@zariumsheridan3488 5 жыл бұрын
So much for user friendliness of managed languages :))) So the next step is to introduce manual memory management, C++ RAII style. Oh wait, "using" is basically just that)) I like "using" without the braces. feels almost like C++ :) Or we could just go back to C++ )))
@JosephF.
@JosephF. 5 жыл бұрын
but the whole point is that with managed languages, you can just not worry about this stuff if you don't need bleeding edge performance
@ComposerJoakimS
@ComposerJoakimS 5 жыл бұрын
Aren't these all examples of flaws in the compiler that will be fixed within a few months or a year? If not, why are the compiler designers not fixing them, relieving every programmer the burden of having to do low-level optimisation manually over and over again?
@samuelgrahame3617
@samuelgrahame3617 5 жыл бұрын
Just delete your code. No allocations
@junpeiiori4720
@junpeiiori4720 5 жыл бұрын
Genius!
@mementomori6992
@mementomori6992 5 жыл бұрын
TED talk style presentation is an appeal to the lowest common denominator, which somehow seems wrong when the topic is more technical than snorting crayons.
@onionhammer
@onionhammer 5 жыл бұрын
foreach allocates...
@Tyrrrz
@Tyrrrz 5 жыл бұрын
foreach doesn't allocate, GetEnumerator() does, which is what Matt is talking about :)
@BryonLape
@BryonLape 4 жыл бұрын
So....write in C# 1.1 and ignore everything add after that.
@mikaelfrosthage4375
@mikaelfrosthage4375 4 жыл бұрын
Generics from version 2 is pretty useful too, so you don't have to box value types when using ArrayList etc.
@ChaotikmindSrc
@ChaotikmindSrc 5 жыл бұрын
Yes , let's write code without allocation in a memory managed language, or how to say "memory management is so bad i have to get around it to do my job"...... i'm back to c++, it was an horrible idea to learn C#, i inadvertently supported that shit.
@Tyrrrz
@Tyrrrz 5 жыл бұрын
The whole point was that prior to Span, writing in C# meant that you'd rather have less efficient memory usage in return for memory safety. With Span you have the same memory safety with completely unhindered memory efficiency.
@ChaotikmindSrc
@ChaotikmindSrc 5 жыл бұрын
@@Tyrrrzi get the point but my view is still valid; YMMV, but anyway i never had big problems with memory alloc in c/c++, and at least i get some serious perf. The only clear advantage i have to use c# is because it is fast to build GUI heavy software, but that could very well change in the future, if let's say, a framework like JUCE had a nice visual editor plugin for your IDE of choice.
@Tyrrrz
@Tyrrrz 5 жыл бұрын
@@ChaotikmindSrc I don't think saying "memory management is so bad i have to get around it..." is right, it's fairer to say "memory management got to a point where it can have near-unmanaged performance without the downsides of being able to shoot myself in the foot"
@ChaotikmindSrc
@ChaotikmindSrc 5 жыл бұрын
@@Tyrrrz I 'm probably the kind of guy who like to be able to shot himself in the foot ! But i'm very probably biased anyway since i'm doing industrial programming, doing lot's of math intensive stuff, dsp and so on. lately i was forced to convert a whole stewart gough platform simulation software to c++ because of maths performances, and i'm probably a bit pissed ;)
@Tyrrrz
@Tyrrrz 5 жыл бұрын
@@ChaotikmindSrc that's fine :) I have nothing against C++, was just pointing out that your original comment is unnecessary harsh
@sealsharp
@sealsharp 8 ай бұрын
34:12 Defensive copy on method calls: At the time of this talk ( June 2019 ) the feature called "readonly members" did not exist yet. It premiered in C#8 in September 2019. Readonly members allow to mark methods and property getters on structs as readonly and the compiler enforces that these methods do not change the internal state of the struct. Accessing readonly members avoid the defensive copy on structs that are not as a whole readonly.
Turbocharged: Writing High-Performance C# and .NET Code - Steve Gordon
1:01:12
Change your habits: Modern techniques for modern C# - Bill Wagner
55:46
NDC Conferences
Рет қаралды 251 М.
“Don’t stop the chances.”
00:44
ISSEI / いっせい
Рет қаралды 62 МЛН
Writing C# without allocating ANY memory
19:36
Nick Chapsas
Рет қаралды 153 М.
C# 8 and Beyond - Filip Ekberg
54:15
NDC Conferences
Рет қаралды 18 М.
Are events in C# even relevant anymore?
16:19
Nick Chapsas
Рет қаралды 171 М.
Correcting Common Async/Await Mistakes in .NET - Brandon Minnick
1:00:11
NDC Conferences
Рет қаралды 167 М.
Stackalloc and Spans
30:17
Coding Tutorials
Рет қаралды 11 М.
Lowering in C#: What's really going on in your code? - David Wengier
44:39