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.
@HenrikRClausen5 жыл бұрын
I applied this to my code today - and got a performance gain that looks like an order of magnitude!
@osten2223125 жыл бұрын
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
@sacredgeometry5 жыл бұрын
Or you know just allocate ahead of time and just reuse objects with different configurations instead of deallocating them.
@sealsharp8 ай бұрын
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.codefactory3 жыл бұрын
Wow, such a great presentation with lots of advanced concepts, thank you for all this Matt, appreciate it!!!
@galandilvogler85775 жыл бұрын
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_5 жыл бұрын
C# slowly turns into C++.. the better part of it :)
@FaithfulGeneral5 жыл бұрын
haha never will it ever. ;)
@DEBBAH19073 жыл бұрын
C# now in 2021 is like a mix of C++ python and javascript sadly
@davidklempfner8263 жыл бұрын
@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.
@FastFSharp3 жыл бұрын
Fantastic talk! This is exactly the kind of content I have been searching for!
@sken13013 жыл бұрын
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?
@kobby2g85 жыл бұрын
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.
@StephenJWalter5 жыл бұрын
Excellent presentation.
@lollo47112 жыл бұрын
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)
@wim19835 жыл бұрын
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?
@samuelgrahame36175 жыл бұрын
Idbconnection is a class so no point using ref. As it is a reference type. It does that by default.
@wim19835 жыл бұрын
@@samuelgrahame3617 I think so.
@logank.705 жыл бұрын
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_Trooper3 жыл бұрын
I want a Span that works with files and memory mapped files.
@Grimlock19795 жыл бұрын
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)
@PatrickKellyLoneCoder5 жыл бұрын
Context my dude. He's clearly talking about .NET world specifically.
@Grimlock19795 жыл бұрын
Context is irrelevant. "reference types are passed by reference" is a wrong thing to say. But I hear it all the time.
@DavidTimovski4 жыл бұрын
@@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.
@DavidTimovski4 жыл бұрын
@@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.
@caioavidal4 жыл бұрын
Very useful knowledge
@wim19835 жыл бұрын
I cannot start to imagine to rewrite all the linq expression to foreach and if...
@balazsarva19915 жыл бұрын
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.
@wim19835 жыл бұрын
@@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.
@wudewang99475 жыл бұрын
Great explanation.
@bultvidxxxix99735 жыл бұрын
1:24 do I hear applause?
@PankajNikam5 жыл бұрын
Must be another conference going on right beside the one that we are watching in this video.
@blakersquakers5 жыл бұрын
Always be measuring was a hit with the crowd!
@LuigiTrabacchin4 жыл бұрын
thumb up for the initial DON'T and measure it
@LuigiTrabacchin4 жыл бұрын
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
@loam5 жыл бұрын
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?
@balazsarva19915 жыл бұрын
"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.
@XTK0015 жыл бұрын
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.
@samuelgrahame36175 жыл бұрын
@@XTK001 also it is used for releasing non manages objects as they are not collected by gc.
@Tyrrrz5 жыл бұрын
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.
@Beni98195 жыл бұрын
Which UI is this?
@swstein5 жыл бұрын
Jetbrains Rider. It's great.
@luiscantero4 жыл бұрын
Jetbrains Rider
@ComposerJoakimS5 жыл бұрын
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.
@MobilTemp4 жыл бұрын
What? Herself?
@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_Trooper10 ай бұрын
@@VectorTwelve good point, there are only two famous female programmers.
@7th_CAV_Trooper10 ай бұрын
@@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.
@ivandrofly5 жыл бұрын
Good stuff!
@sergekg2kg8445 жыл бұрын
Perfect talk related to C# performance. Now C# and C++ equal in performance using these techniques.
@RandomGuy-we2mn5 жыл бұрын
Isn't c# faster?
@bangonkali5 жыл бұрын
@@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. 😂😂😂
@Adolf1Extra5 жыл бұрын
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.
@serges4675 жыл бұрын
@@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-we2mn5 жыл бұрын
@@bangonkali I was joking about speed :)
@ivandrofly5 жыл бұрын
Very concise!
@anon_y_mousse2 жыл бұрын
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.
@zariumsheridan34885 жыл бұрын
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.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
@ComposerJoakimS5 жыл бұрын
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?
@samuelgrahame36175 жыл бұрын
Just delete your code. No allocations
@junpeiiori47205 жыл бұрын
Genius!
@mementomori69925 жыл бұрын
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.
@onionhammer5 жыл бұрын
foreach allocates...
@Tyrrrz5 жыл бұрын
foreach doesn't allocate, GetEnumerator() does, which is what Matt is talking about :)
@BryonLape4 жыл бұрын
So....write in C# 1.1 and ignore everything add after that.
@mikaelfrosthage43754 жыл бұрын
Generics from version 2 is pretty useful too, so you don't have to box value types when using ArrayList etc.
@ChaotikmindSrc5 жыл бұрын
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.
@Tyrrrz5 жыл бұрын
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.
@ChaotikmindSrc5 жыл бұрын
@@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.
@Tyrrrz5 жыл бұрын
@@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"
@ChaotikmindSrc5 жыл бұрын
@@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 ;)
@Tyrrrz5 жыл бұрын
@@ChaotikmindSrc that's fine :) I have nothing against C++, was just pointing out that your original comment is unnecessary harsh
@sealsharp8 ай бұрын
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.