Re: My takeaway from this article...
Linkers no longer do what they used to.
When you used a linker to produce a statically linked binary using proper libraries (it's interesting that ancient versions of UNIX used the "ar" command to manage libraries, which was extended to create "tar"), the linker would extract each .o file from the library before linking that into the binary. The scope of the .o file was exactly what the creator of the object wanted. You wanted a single subroutine, put it into it's own .o file. You want a large library of subroutines, include them all in the .o. The linker would include the whole of the .o file in the resultant binary (which, because it was statically linked, would load quickly, and so long as the system-call layer from the OS did not change, became largely OS version independent!)
When dynamic linking started to be used, because of the way that it was integrated into the memory segment model of many systems, it was not really possible to do this at the object file basis. Many shared libraries occupied an entire memory segment, so it was best to make them as large and all-encompassing as possible to reduce the number of memory segments used. The linker really now just becomes a dependency checker, to make sure that all of the symbols required by the program are actually present in the included library, and much of this has to be done at run time!
And anyway, they were all shared so what did it matter if you pulled in the whole library! You would save space because there would only be one copy of, say, the C library for all of the applications that were running on the system
This can cause problems. I don't know about Windows, but on Linux and most UNIX systems with shared libraries, it can be difficult to work out the true size of a program. Most simple tools will tell you the size of the code segment(s) in use by a program, but they will count the entirety of the code including the shared libraries. This means that if you are looking at several programs that all use the same shared library, that shared library will actually be counted multiple times.
There are more sophisticated tools to look at exact memory usage (on AIX there is svmon), but actually untangling what they say is difficult.
Bring this up to date. Modern applications are built on layers and layers of tools. And each layer will include their own variable, self-modifying code (think things like Perl modules or Java Class libraries) or more traditional shared librarieslibraries And if these are arranged as dynamically linked libraries, with the premise that each library has to include as much as possible, these applications become absolutely huge!
Add to this the memory space segregation that is required for threaded applications now because of security concerns (remember, the original SunOS Lightweight processes and the following Posix thread model shared the code and data space between threads to make them, um, lightweight), and we now have a situation where every tab in the browser is effectively a full heavyweight process, not really the thread that used to drive it.
To add insult to injury, current containerized formats like Snap, Flatpak and appimage ship the entire library dependency set in the container for each application. So a large application packaged like this will have it's own extensive set of the Linux userland, meaning that you can have many, many versions of things like the C library, for example, running on your system. This is the diametric opposite of the original thinking behind shared libraries!
I want to go back to the days of the more-static syscall interface, and static linking of applications, rather than this bloatfest that modern day application development forces us to carry! It does have it's problems, but just think how fast everything would run!