4 ms·
In practice, memory is the largest pool of resources a programmer has to manage. In the 1960s, a computer may only have 1000-words or 2000-words of memory, and
by dragontamer 4y ago
In practice, memory is the largest pool of resources a programmer has to manage. In the 1960s, a computer may only have 1000-words or 2000-words of memory, and you could manage it all manually. Memory location#45 means blah, Memory location#80 means bar, etc. etc.
This form of variable-allocation is now done automatically (ex: int foobar; will automatically manage a memory location to be representing a 4-byte value named foobar). This is the simplest way of managing memory (even on extremely constrained modern platforms like ATTiny4, which only has 256 Bytes of RAM. BTW: I do suggest people play with microcontrollers, if only to improve your skills at programming in constrained environments).
But as you start having to efficiently manage more than that: a million bytes (aka: 1MB), or a billion bytes (aka: 1GB), more complex patterns arise. In particular, a program may not know how much memory it needs at compile time, and may need to shift the amount of memory usage arbitrarily upon the user's work pattern.
For example: lets say you are writing a web-client, and your user is going to visit the webpage www.google.com. How much memory should you allocate for it? Well, you don't know. You have to start downloading the page before you even know how much memory it will use. (Upon talking to www.google.com, the Google Server says in the HTTP protocol how many bytes the webpage will take up, giving the program an opportunity to allocate memory at that point). To properly store the webpage, you need a memory-management scheme.
-------------
Modern languages have two patterns for more complex memory management like the "browse to www.google.com" example I described above.
1. C's malloc-and-free pattern. The programmer reserves memory with malloc or calloc. And the programmer says that they're done using the memory with free(), allowing a future malloc() call to recycle the memory.
2. Garbage collection, aka malloc-only. The system automatically determines when memory "should be freed". Though more complex to program, its been popular even as early as the 1970s. It turns out that programmers are pretty bad at writing free() correctly in practice.
There's also the "automatic" memory management implemented by the compiler. This is called "stack allocation" in most cases, and IMO is important to understand how it works... if only because of how efficiently it recycles the L1 Cache and speeds up your program. But we can talk about that some other time!
- msla 4y ago> Modern languages have two patterns for more complex memory management I count four, even if you discount pure static pre-allocation: 1. Manual dynamic memory allocation and deallocation, as with malloc() and free() and, in C++, new and delete, possibly augmented with things like RAII which don't fundamentally change it. 1.5. Reference counting lives somewhere in here, between pure manual allocation/deallocation and true garbage collection, in that it automates some aspects of resource management but needs some extra manual help to deal with circular data structures that real garbage collection has no problem with. 2. Garbage collection, in multiple different algorithms and optimizations. 3. Linear types, which enable static lifetime analysis, as is done in Rust. 4. Purely declarative languages and other extremely high-level languages that effectively take it out of the programmer's hands entirely and handle everything implicitly.
- dragontamer 4y agoReference counting is Garbage Collection (and is Python's method of Garbage collection). Borrow Checker is... hmm... I guess that's a new-ish pattern. Its inspired from C++ unique_ptr and auto_ptr (now obsolete, use unique_ptr instead). I'd say that Borrow Checker is still manual memory management, except the compiler writes the free() for you. #4: purely declarative languages and such is going to be garbage collected in practice. ---------- So 1.5, 2, and 4 are all garbage collection. #3 / Rust's borrow checker is debatable. I'm still inclined to call that manual malloc/free(), even if the compiler handles the free() for you. Because the compiler can only free() if you code it in the exact way that Rust (or C++ unique_ptr) expects the memory to be used.
- msla 4y agoApparently, Python split the difference and uses reference counting alongside garbage collection: https://rushter.com/blog/python-garbage-collector/ https://rushter.com/blog/python-garbage-collector/ However: > I'd say that Borrow Checker is still manual memory management, except the compiler writes the free() for you. And: > #4: purely declarative languages and such is going to be garbage collected in practice. My point is to catalog the different ways programmers have to think about resource usage, not implementation details. Python is a GC'd language, and unlike C++ with smart pointers, because it doesn't make the programmer manually manage memory in order to avoid a leak, and regular expressions and SQL are high-level in that the languages don't even offer a way to express the concept of resource management.