|
more falafel please posted:- you still have to manage memory/resources, in that your code needs to be Correct or you'll have tons of leaks. If you're writing a microservice that's alive for 100ms, this is fine, I guess This is the PHP execution model. Request comes in, program spits out a response and terminates without ever actually doing any garbage collection.
|
# ? Nov 8, 2021 17:56 |
|
|
# ? May 29, 2024 15:06 |
|
more falafel please posted:We have this argument every few months but downsides: It's a common mistake to think that GCd languages protect against memory leaks. They don't, but they protect against use-after-frees which is arguably more important. (malloc/free is also far less predictable than people tend to think, though magnitudes less noticeably so than GC).
|
# ? Nov 8, 2021 18:02 |
|
OddObserver posted:It's a common mistake to think that GCd languages protect against memory leaks. They don't, but they protect against use-after-frees which is arguably more important. Right, plus if you're doing anything real-time, any temporary allocations are your enemy, even if they're handled "correctly". Short-term allocations mean GC is going to run eventually (or you run out of memory, either one is bad). In, say, a game that has 16ms to render a complete frame, GC running during anything interactive is Very Bad.
|
# ? Nov 8, 2021 18:13 |
|
more falafel please posted:Right, plus if you're doing anything real-time, any temporary allocations are your enemy, even if they're handled "correctly". Short-term allocations mean GC is going to run eventually (or you run out of memory, either one is bad). In, say, a game that has 16ms to render a complete frame, GC running during anything interactive is Very Bad. The bigger problem is that the illusion makes people (primarily those who haven't shipped similar projects before) believe they don't need to care. And it's incredibly difficult to try to care about resource management after you've built up a few hundred thousand lines of code and need to hit a ship date. I've spent way more time educating people about why they still need to care about memory than I would in environments where it's more explicit that you need to care. This is also the most amusing thing about people who maintain c++ elitism in comparison to something like unity. At least they usually have the facilities to resolve the problems. IMO it's a much harder problem to deal with in a managed language, if only due to the cultural issues and the need to educate junior staff on needing to care about something that "is done for them".
|
# ? Nov 8, 2021 18:22 |
|
If you want predictability you want to start doing things like arenas - grab a chunk of memory for each request, allocate linearly within that chunk for any intra-request allocations, release the entire chunk back to a shared pool when done. Smooth and simple and fast, no rummaging around freelists or dealing with fragmentation.
|
# ? Nov 8, 2021 18:24 |
|
leper khan posted:The bigger problem is that the illusion makes people (primarily those who haven't shipped similar projects before) believe they don't need to care. And it's incredibly difficult to try to care about resource management after you've built up a few hundred thousand lines of code and need to hit a ship date. Yup. We did a port of a Unity game to console and had two engineers assigned to memory optimizations (mostly just doing pooled object allocs so that GC was more predictable and could be handled at level transition) for over a year. Not that you don't have to care about that stuff in, say UE4, but liberal use of ref-counted smart pointers and auto allocation means that you have to explicitly care about it. Resource management isn't *hard*, but you need to do it. You still need to do it in managed languages/environments, and it's harder to do.
|
# ? Nov 8, 2021 18:38 |
|
more falafel please posted:Yup. We did a port of a Unity game to console and had two engineers assigned to memory optimizations (mostly just doing pooled object allocs so that GC was more predictable and could be handled at level transition) for over a year. Not that you don't have to care about that stuff in, say UE4, but liberal use of ref-counted smart pointers and auto allocation means that you have to explicitly care about it. Resource management isn't *hard*, but you need to do it. You still need to do it in managed languages/environments, and it's harder to do. My biggest pain point in C#/Unity is not having RAII semantics or deterministic calling of finalizers. Scope operator is so useful in c++. Close second is equality comparison on null being so bananas that eliminating them has been the largest single performance improvement on multiple projects. That said I just got a job where we have a custom engine and I desperately look forward to maneuvering to the group working in unity.
|
# ? Nov 8, 2021 18:50 |
|
leper khan posted:Close second is equality comparison on null being so bananas that eliminating them has been the largest single performance improvement on multiple projects. Wait what
|
# ? Nov 9, 2021 14:23 |
|
Phobeste posted:Wait what I'm guessing it's the possible operator overloading of == / .Equals() screwing up hot paths? I remember one time I had to write a small piece of code for a .NET library that needed to efficiently check for nulls and only nulls, and the correct way to do so was to use the static invocation Object.ReferenceEquals(butt, null).
|
# ? Nov 9, 2021 14:42 |
|
Phobeste posted:Wait what They overload == to call out to native code so that a check of a == null returns true if the native object is destroyed even if the C# reference still exists. https://blog.unity.com/technology/custom-operator-should-we-keep-it
|
# ? Nov 9, 2021 14:48 |
|
Unity
|
# ? Nov 9, 2021 14:59 |
|
Phobeste posted:Wait what Admiral H. Curtiss posted:They overload == to call out to native code so that a check of a == null returns true if the native object is destroyed even if the C# reference still exists. Exactly that. In addition to the perf issues, you also don't get to use the `?.` operator on anything that inherits `UnityEngine.Object` because it sidesteps their overload (because the CLR assumes you're not _that_ dumb) and gives you inconsistent and nondeterministic results. At least the common IDEs warn you about that. Truly an exemplar of carmacks law. Xarn posted:Unity
|
# ? Nov 9, 2021 15:39 |
|
leper khan posted:My biggest pain point in C#/Unity is not having RAII semantics or deterministic calling of finalizers. Scope operator is so useful in c++. Close second is equality comparison on null being so bananas that eliminating them has been the largest single performance improvement on multiple projects. I've never done game dev and this is a sincere question because I'm curious: What do you need deterministic finalizers for that IDisposable won't get you?
|
# ? Nov 9, 2021 16:06 |
|
raminasi posted:I've never done game dev and this is a sincere question because I'm curious: What do you need deterministic finalizers for that IDisposable won't get you? The inability to fail to call Dispose() at the correct time and the ability to rely on scope to manage lifetimes instead of the GC so I can accurately manage frame time. IDisposable mostly just gives me something to clean up things the GC won't capture at GC time. And trying to use it for other things is fairly error prone.
|
# ? Nov 9, 2021 16:14 |
|
raminasi posted:I've never done game dev and this is a sincere question because I'm curious: What do you need deterministic finalizers for that IDisposable won't get you? The use-site has to opt-out from RAII by doing something visibly weird. The use site has to opt-in to calling IDisposable.
|
# ? Nov 9, 2021 16:16 |
|
A coding horror all of my own (and maybe Python library developers) doing. Did you know that when retrieving the shape of an image, the output tuple is different between OpenCV and Pillow? You might guess that if you're collecting image data, correctly assigning the height to the "height" feature, as well as the width to the "width" feature is important, and if you, say, incorrectly assume that the first element returned from Image.size is the height of the image, then all your data for your images is going to be wrong. Yay! I wasted a work day wondering why the data I collected wasn't playing nice. Turns out the data I collected disagreed with reality and that's not good, imagine that.
|
# ? Nov 9, 2021 16:18 |
|
leper khan posted:The inability to fail to call Dispose() at the correct time and the ability to rely on scope to manage lifetimes instead of the GC so I can accurately manage frame time. Xarn posted:The use-site has to opt-out from RAII by doing something visibly weird. The use site has to opt-in to calling IDisposable. Ah, so is this just "you have to remember the using"? (I'm not being snarky, that's a fine objection, I just want to make sure I understand.)
|
# ? Nov 9, 2021 16:20 |
|
I feel like game programming is a somewhat special case here. For most general programming the pauses in modern GCs aren't that significant, it's just this thing that's carried over from the 1990s when it was more of a problem. A modern GC is going to have thread local allocation buffers so allocations are just incrementing a pointer, moving collection so actual garbage has no cost and only the absolute minimum possible work saved for a stop the world pause. Like if it's not enough for your situation, that's fair but there's a lot of situations where it's perfectly fine. Additionally I think it's fine for memory to have different lifecycle semantics than other forms of resources and can be helpful in that sense. Take a situation where a program needs to get some data from a server at some URL. There's multiple independent threads that may need data from several related URLs but they can share the cached data if they hit the same resource within some time window. This is something where a separate object with a lifecycle independent of the threads to do the downloads (with explicit lifecycles for the network connection), parsing and reinflation of the data can save work for all the worker threads. It can then keep the resulting cache for its lifecycle and discard old data as needed. Where GC is helpful is that this can hand references to its (presumably immutable) shared data without fears of that data being still live when it wipes it for staleness. Once the shared object is truly no longer touched it can be deleted safely but that's not clear to the program itself without a lot of communication between the threads or simply using GC.
|
# ? Nov 9, 2021 16:25 |
|
I haven’t thought this through, but an optional warning when you don’t use a using statement with an IDisposable could maybe help that problem. Guess it doesn’t do anything for instances with a non-local scope, though.
|
# ? Nov 9, 2021 16:26 |
|
You can also store it as a class member and get the equivalent of a class which has an IDisposable member automatically itself being IDisposable and doing the right thing by default. It's just generally a lot less error prone than having to do things manually, just like automatic memory management is a lot less error-prone than manual memory management.
|
# ? Nov 9, 2021 16:26 |
|
raminasi posted:Ah, so is this just "you have to remember the using"? (I'm not being snarky, that's a fine objection, I just want to make sure I understand.) Yeah, the thing we aren't saying that you also need to keep in mind is the average tenure in the game industry is very short and trends to the beginning of people's careers. There's not a small amount of cleaning up after juniors and chasing bad patterns. Combined with a different set of priorities than general software, and some weirdly lacking areas of common practice (I _still_ run into people who claim game code can't be tested) things can get weird. Games sort of sit on the edge where the convenient things are nice until they're the root cause of needing to spend an extra couple months of dev time reworking systems. I would unironically rather write game clients in C than C#, but that's not generally an option that's been available to me. I did not hold that view earlier in my career. Games backends these days look a lot like web backends. So there's less drift there in the problems you run into, how you might think about them, and their solutions.
|
# ? Nov 9, 2021 16:45 |
|
Protocol7 posted:A coding horror all of my own (and maybe Python library developers) doing. The fault here is with those libraries - both of them - for returning tuples, instead of objects with named attributes for Height and Width. NihilCredo posted:I'm guessing it's the possible operator overloading of == / .Equals() screwing up hot paths? Correct me if I'm wrong but that's exactly what "is null" does, and until they added "is null" to the language it was the single correct way to compare with null any time you were implementing comparison for a type that overrides == and !=.
|
# ? Nov 9, 2021 18:15 |
|
Hammerite posted:The fault here is with those libraries - both of them - for returning tuples, instead of objects with named attributes for Height and Width. It's possible that one of the libraries has a deeper fault - the jpeg file format allows you to specify the orientation of the image instead of just assuming that the data starts at the topleft. Careless library writers don't pay attention to that and can give you images that are rotated by 90 degrees or flipped.
|
# ? Nov 9, 2021 18:33 |
|
Qwertycoatl posted:It's possible that one of the libraries has a deeper fault - the jpeg file format allows you to specify the orientation of the image instead of just assuming that the data starts at the topleft. Careless library writers don't pay attention to that and can give you images that are rotated by 90 degrees or flipped. This actually burned me a bit too because of I believe mixed usage of PIL and OpenCV in this third party library I'm using (mmdetection, if anyone is curious). One of them handles EXIF transpositions properly when loading an image from disk and the other does not. Simple solution was to just burn through all the images, apply necessary EXIF transpositions and re-save the image to disk and strip EXIF.
|
# ? Nov 9, 2021 18:40 |
|
raminasi posted:Ah, so is this just "you have to remember the using"? (I'm not being snarky, that's a fine objection, I just want to make sure I understand.) Basically yeah, also automatic composition (in RAII model types propagate disposal automatically, in IDispose afaik they do not).
|
# ? Nov 9, 2021 18:47 |
|
more falafel please posted:We have this argument every few months but downsides: The Unity people wanted to make their basic engine in C#, so they settled on a subset of C# that circumvents the GC. Some early reporting here
|
# ? Nov 9, 2021 19:15 |
|
The DOTS stuff just seems like a workaround for C# being a pretty poor language choice for games. I’d rather work in a language that natively supports controlling memory layout than hack it into some other language. It’s also Unity in the 2020s so you can’t trust that it’ll ever actually be feature complete before they deprecate it in favor of some other shiny thing.
|
# ? Nov 9, 2021 19:48 |
|
chglcu posted:The DOTS stuff just seems like a workaround for C# being a pretty poor language choice for games. I’d rather work in a language that natively supports controlling memory layout than hack it into some other language. It’s also Unity in the 2020s so you can’t trust that it’ll ever actually be feature complete before they deprecate it in favor of some other shiny thing. DOTS is a very troubled project. That's already essentially happened to it twice. It's important to realize that though unity frames themselves as a game engine company to the games industry, essentially all of their revenue is from ads.
|
# ? Nov 9, 2021 21:22 |
|
Protocol7 posted:A coding horror all of my own (and maybe Python library developers) doing. This comes down to what's convenient for processing vs parlance and is encountered at some point by everyone who works with image data. When we talk about images we tend to order things by (width, height), but in row-major ordering the data is stored as (height, width). Note that PIL's size attribute doesn't say anything about how the data is stored, just that it returns a tuple of (width, height). Numpy and opencv return the actual shape of the array in memory, which is (height, width) if you use default row-major ordering This discrepancy exists because PIL sucks poo poo through a straw, hth
|
# ? Nov 9, 2021 22:29 |
|
leper khan posted:DOTS is a very troubled project. That's already essentially happened to it twice. And just now they've acquired WETA, so look forward to some half assed integration between the Unity engine and WETAs tooling, that will never leave alpha
|
# ? Nov 9, 2021 22:30 |
|
Hammerite posted:The fault here is with those libraries - both of them - for returning tuples, instead of objects with named attributes for Height and Width. Both libraries provide those values as attributes of the image objects, but they return tuples if you want all of the dimensions It'd be really dumb to return some sort of Size object instead of an iterable of integers and I think this is a sign that you have a severe case of Java Poisoning QuarkJets fucked around with this message at 22:37 on Nov 9, 2021 |
# ? Nov 9, 2021 22:35 |
|
QuarkJets posted:Both libraries provide those values as attributes of the image objects, but they return tuples if you want all of the dimensions Having a method that returns a size map would be nice for these situations tho. You can have both it's no biggie.
|
# ? Nov 9, 2021 23:36 |
|
QuarkJets posted:It'd be really dumb to return some sort of Size object instead of an iterable of integers and I think this is a sign that you have a severe case of Java Poisoning What
|
# ? Nov 9, 2021 23:53 |
|
It would be really dumb to [do the most sensible thing in the circumstances], clearly what it should do instead is [obviously awful cowboy coder bullshit]. If you disagree then you're one of the bad people, and my enemy.
|
# ? Nov 9, 2021 23:59 |
|
Hammerite posted:It would be really dumb to [do the most sensible thing in the circumstances], clearly what it should do instead is [obviously awful cowboy coder bullshit]. If you disagree then you're one of the bad people, and my enemy. I think someone here needs to be sentenced to spending time with STL map containers. A few ->second.first's and the desire to use these sorts of types for public interfaces flows right out of the window.
|
# ? Nov 10, 2021 00:04 |
|
QuarkJets posted:Both libraries provide those values as attributes of the image objects, but they return tuples if you want all of the dimensions An object responding to "width" and "height" doesn't exclude it also being an iterable of integers? It's strictly more useful.
|
# ? Nov 10, 2021 00:21 |
|
I don't know enough about OpenCV to know if it does this sanely but you may reasonably want a data processing library to be able to rearrange your WxHx3 RGB image to an 3xHxW image for an algorithm that prefers a channel-column-row traversal order, or to a 16x16x3x(H/16)x(W/16) tiling, or something worse. You quickly reach the point at which trying to shoehorn in contextually specific notions that one dimension is going to be "width" and another "color channel" is more confusing than helpful. If that's the standard use case then it makes sense for your library to import all its data as abstract multidimensional arrays to begin with and let the programmer slice, rearrange and transform them freely. PIL and Pillow are not abstract data processing libraries, probably should have named properties for their dimensions, and are generally hot garbage last I checked. I'd suggest OpenImageIO, which incidentally has all that sort of data in a ImageSpec class full of named properties including width and height, but installing OIIO for just python is likely still a pain.
|
# ? Nov 10, 2021 02:20 |
|
Xerophyte posted:I don't know enough about OpenCV to know if it does this sanely but you may reasonably want a data processing library to be able to rearrange your WxHx3 RGB image to an 3xHxW image for an algorithm that prefers a channel-column-row traversal order, or to a 16x16x3x(H/16)x(W/16) tiling, or something worse. You quickly reach the point at which trying to shoehorn in contextually specific notions that one dimension is going to be "width" and another "color channel" is more confusing than helpful. If that's the standard use case then it makes sense for your library to import all its data as abstract multidimensional arrays to begin with and let the programmer slice, rearrange and transform them freely. That's the thing though, PIL images do have named properties for width and height. They are named "width" and "height", and they are integers. The OP used a method that happens to return tuple of (width, height)
|
# ? Nov 10, 2021 03:50 |
|
recent versions of c# and .net have recognized that sometimes allocations are bad, and have added a bunch of (pretty niche) features to give devs more control over memory while still remaining memory-safe. it'll be interesting to see if these end up being used anywhere and/or making a difference
|
# ? Nov 10, 2021 05:57 |
|
|
# ? May 29, 2024 15:06 |
|
gently caress speed, gently caress optimizing memory just write good code that is also easy to read and understand If the cost is some expensive invisible operation is invoqued when doing ==. So be it. Edit: this thread need good old WTFeries. I am doing my part.
|
# ? Nov 10, 2021 08:56 |