4 ms·
> files flushed/closed, memory freed, radiation-emitter disabled All of this is performed by destructors/GC cleanup/Drop in most languages. > That's why even
by akiselev 6y ago
> files flushed/closed, memory freed, radiation-emitter disabled
All of this is performed by destructors/GC cleanup/Drop in most languages.
> That's why even in safe Rust code, it's possible to leak memory
It's possible to leak memory through circular references and lazy evaluation in all languages AFAIK.
> e.g. shut down without calling the "switch off the radiation emitter" destructor on a medical device.
Unsafe unwinding is possible in any language, including one with linear types. If the runtime crashes, there's nothing to guarantee their one-time use.
- logicchains 6y ago>All of this is performed by destructors/GC cleanup/Drop in most languages. Most GC languages don't guarantee that finalisers will run on shutdown, and no languages I'm aware of guarantee that destructors will run. For really safety critical applications it's not enough that it works fine most of the time; it needs to provide an iron-clad guarantee (as e.g. Ada with Spark can provide for many things). When writing a library it's not possible to guarantee the user will use it correctly when the compiler isn't able to enforce this. >It's possible to leak memory through circular references and lazy evaluation in all languages AFAIK. In a garbage-collected language, circular references alone aren't enough to cause memory leaks, as if the circle is not referenced transitively from the root object then it will still be collected. >Unsafe unwinding is possible in any language, including one with linear types. If the runtime crashes, there's nothing to guarantee their one-time use. That's true and unfortunate. But linear types at least guarantee that with orderly shutdown, every destructor will be called correctly.
- pjmlp 6y agoThere are other ways to release resources in GC languages, and finalisers are not the right way to do it. In languages like Java, C#, F#, it is quite easy to have a lint check that gives a compiler error when an IAutoCloseable or IDisposable isn't used with a try/using block, just like RAII, with a bit of static analysis help.
- logicchains 6y agoYep, but that doesn't help so much when you're writing a framework or library and want to ensure the user can't mess it up (although current Haskell couldn't help with that either, given there's no way to prohibit the user writing unsafe code).
- pjmlp 6y agoJust like in languages like C++ you cannot force stack allocation/global memory segments, which is the only way to make RAII work. A new without delete, not only causes a memory leak, it also leaks whatever else could be released by the destructor. Same applies to Rust when heap memory gets forgotten.
- AnimalMuppet 6y ago> Just like in languages like C++ you cannot force stack allocation/global memory segments, which is the only way to make RAII work. Could you explain a bit more about what you mean here? To me, RAII is about how the constructor is written, and stack allocation/global memory segments are about where the object is created. I don't see any connection between the two. For example, if I have a class with a custom allocator that allocates from its own arena, I can still do RAII on the members of objects of that class... can't I?
- pjmlp 6y agoYeah, but how are you supposed to release the data stored in the area and the owning class, if the destructor doesn't get called? As an example (ignore possible compile errors), // in mylib.h namespace mylib { template<class allocator = default_arena> class ArenaString final { public: ArenaString(); ~ArenaString(); // several String related methods private: ArenaAllocator<allocator> stringData; }; // several utility functions ArenaString* StringFactory() { return new ArenaString(); } } // now on main.cpp #include "mylib.h" void myLeakyFunction() { auto strPtr = mylib::StringFactory(); // do something with strPtr //oops, strPtr is now gone and ArenaString::~ArenaString() won't get called } Alternatively, which I think is the main point of your question, one could call something like myArena::clean() somewhere up the call stack to myLeakyFunction. But then the question about class instances surviving the region as empty shells with a corrupt state in their stringData member data arises. While this example is made on purpose to illustrate my point, on big code bases (specially with libraries that one doesn't have any kind of control) it can lead to bad code that prevents RAII patterns to work as expected. Code that most developers on the team won't even realize it is there and probably will spend hours trying to find out what is wrong with the memory management.