Static linking vs dynamic linking
Asked Answered
E

16

494

Are there any compelling performance reasons to choose static linking over dynamic linking or vice versa in certain situations? I've heard or read the following, but I don't know enough on the subject to vouch for its veracity.

1) The difference in runtime performance between static linking and dynamic linking is usually negligible.

2) (1) is not true if using a profiling compiler that uses profile data to optimize program hotpaths because with static linking, the compiler can optimize both your code and the library code. With dynamic linking only your code can be optimized. If most of the time is spent running library code, this can make a big difference. Otherwise, (1) still applies.

Editheditha answered 3/1, 2010 at 0:6 Comment(4)
"With static linking, the compiler can optimize .. the library code" but only if it compiles that too! If you just link to pre-compiled object files, your compiler doesn't get the chance to optimize them.Synesthesia
If that is true, then you are right, but there is some question as to how true that is with modern compilers, if someone can verify this one way or another, that would be great.Editheditha
With a compiler compiling to native code (like most C/C++ compilers) there is no further chance for code optimization. If the code is compiled to some intermediate language (like .Net IL) the JIT compiler is invoke when the library is getting loaded to compile it to native code. That final compilation can get increasingly better with time as the JIT compiler evolves.Tymon
@Eloff: VS2008 does exactly that with LTCG enabled. (The lib files become huge, though..) I've toyed around with it and for someone interested in "what can my compiler do for me", it's nothing short of amazing.Jourdan
S
424
  • Dynamic linking can reduce total resource consumption (if more than one process shares the same library (including the version in "the same", of course)). I believe this is the argument that drives its presence in most environments. Here "resources" include disk space, RAM, and cache space. Of course, if your dynamic linker is insufficiently flexible there is a risk of DLL hell.
  • Dynamic linking means that bug fixes and upgrades to libraries propagate to improve your product without requiring you to ship anything.
  • Plugins always call for dynamic linking.
  • Static linking, means that you can know the code will run in very limited environments (early in the boot process, or in rescue mode).
  • Static linking can make binaries easier to distribute to diverse user environments (at the cost of sending a larger and more resource-hungry program).
  • Static linking may allow slightly faster startup times, but this depends to some degree on both the size and complexity of your program and on the details of the OS's loading strategy.

Some edits to include the very relevant suggestions in the comments and in other answers. I'd like to note that the way you break on this depends a lot on what environment you plan to run in. Minimal embedded systems may not have enough resources to support dynamic linking. Slightly larger small systems may well support dynamic linking because their memory is small enough to make the RAM savings from dynamic linking very attractive. Full-blown consumer PCs have, as Mark notes, enormous resources, and you can probably let the convenience issues drive your thinking on this matter.


To address the performance and efficiency issues: it depends.

Classically, dynamic libraries require some kind of glue layer which often means double dispatch or an extra layer of indirection in function addressing and can cost a little speed (but is the function calling time actually a big part of your running time???).

However, if you are running multiple processes which all call the same library a lot, you can end up saving cache lines (and thus winning on running performance) when using dynamic linking relative to using static linking. (Unless modern OS's are smart enough to notice identical segments in statically linked binaries. Seems hard, does anyone know?)

Another issue: loading time. You pay loading costs at some point. When you pay this cost depends on how the OS works as well as what linking you use. Maybe you'd rather put off paying it until you know you need it.

Note that static-vs-dynamic linking is traditionally not an optimization issue, because they both involve separate compilation down to object files. However, this is not required: a compiler can in principle, "compile" "static libraries" to a digested AST form initially, and "link" them by adding those ASTs to the ones generated for the main code, thus empowering global optimization. None of the systems I use do this, so I can't comment on how well it works.

The way to answer performance questions is always by testing (and use a test environment as much like the deployment environment as possible).

Sullins answered 3/1, 2010 at 0:10 Comment(25)
The resource consumption is basically the code space, which as time goes on is less and less of a concern. If 500K of library is shared between 5 processes that's 2MB savings, which is less than .1% of 3GB of RAM.Bacardi
If the library also shares the same virtual mapping (the same physical and virtual address in all processes), doesn't a dynamic link also save TLB slots in the processor's MMU?Enteron
Also a dynamic link makes it easy to update buggy library code with better versions.Enteron
@Zan It also makes it easy to add buggy code to a working version.Toxoid
This doesn't really address the performance implications, but that may be because (1) is true and they are negligible under most circumstances. You did give a very good overview of the practical implications of dynamic vs static linking under normal conditions.Editheditha
Another case where you should use dynamic linking is in a compiled program with an embedded interpreter which expects to share code with compiled program. For example, a game written in C++ but with Lua extensions which need to load some of the same C++ code via shared libraries. If such an application is statically linked, and some of its code is loaded a "second time" from a shared library, it can cause undefined behavior (in C++ for example it can be a violation of the One Definition Rule, or ODR). There are some ways to work around this, but "hybrid" programs tend to link dynamically.Frontogenesis
An advantage of static linking is it permits the linker to strip out code that is not used, so the memory usage of the application can be reduced. You have to worry about C runtime versions though.Mainmast
@Mainmast : In most executables archives*(format)*, symbols use differents files inside the executables (symbols in executables aren't used by the OS). So since the OS need to interpret the file format, why it would keep the whole file in RAM instead of just copying the binary code for running it. So far, I never found symbols of executables in the memory dumps I ran... but am I wrong?Excaudate
@Excaudate : Afraid I don't understand your comment, but let me try to clarify mine. Assume I have a library built both as a DLL and as a static library. Consider the application that calls a library function. If I link statically, the code for library functions that the application does not use can be ignored by the linker, i.e. the memory usage includes only code that the application actually uses. If I link dynamically, the entire DLL is loaded into memory, so the memory usage may well be greater (delay loading can change when/if the library is loaded).Mainmast
@Mainmast : You said An advantage of static linking is it permits the linker to strip out code that is not used, so the memory usage of the application can be reduced. You have to worry about C runtime versions though. but I think this wrong as striping only involve remove the files which contains symbols in the executable archive. Since it use a separate file (this is true in most executables format) from the executable code, why the OS would need to load it in the RAM since the OS know symbols are not needed. This is what I wanted to mean.Excaudate
I know the question defines C++ but it's worth updating your answer to say that dynamic linking allows different programming languages to cooperate.Giulietta
"Plugins always call for dynamic linking." That's incorrect. Some plugin models such as Apple's AudioUnits can run the plugin in a separate process and use IPC. This is a safer alternative to dynamic linking for plugins (the plugin cannot crash the host). Suggest the answer be updated to "Plugins may require dynamic linking" or similar.Ramakrishna
Hmmm ... I wouldn't have called those plugins, myself, but I suppose they serve a similar purpose.Sullins
@MarkRansom: it is a mistake to think that the resource consumption issue is "just about RAM". The cache space is much more scarce resource than RAM, and dynamic linking also reduces its usage.Clerestory
@MarkRansom If every process statically linked to the standard library, thus duplicating the standard library, then every time a process calls a common function the cache would be invalidated; one common function would be substituted for another with no benefit. Dynamic linking can certainly prevent cache misses.Michellmichella
"Static linking has faster startup time than dynamically linked libraries". Can you please explain the statement ? According to me, in static linked libraries we load all the shared libraries in the executable so it should take more time than dynamically linked libraries during startup.Savagism
@Savagism Hmm. From a standing start (with nothing needed by the program in memory) static linked code should load faster because [a] static linking typically includes only the library functions called (so there is less code to load) and [b] for those who still have spinning drives the seek time to find the start of separate files. But any particular dynamic library might already be in memory (probably is for certain very common libraries), and seek times are trivial on SSDs.Sullins
@dmckee In static linking all libraries required is embedded in the executable at the start itself right ? So as the size is more, it will take more time for the code to load in memory as opposed to dynamic linking where the size of the executable is less during startup right ?Savagism
@Savagism On full service systems static linking only includes those routines from the library that are used by the program. Not the whole library: just the parts that the program uses. Remember how precious the working set size was on the machines of yesteryear: people spent a long time thinking about these things.Sullins
@dmckee So the size of executable has nothing to do with program startup time?Savagism
@Savagism To load a statically linked program you load the program code and that subset of the library code that is used by the program. To load a dynamically linked program you load the program codes alone and the entirety of any libraries not already resident in memory. If none of the libraries were already in memory then the latter can only be larger than the former. Now the bit about 'if non of the libraries were already present' is why the posts says "may" rather than "is".Sullins
@dmckee Ok got it ! Even if all libraries are present in memory, then too dynamic linking would take more time right due to one level of indirection?Savagism
@dmckee Please correct me if I am wrong, execution time calling same function multiply times with same input can be not stable if using dynamic libraries in windows because the operation system must manage the calls and some times code executing is waiting to call the function because there is threads queue and priorities , while static linking has all the code loaded in the memory and do not face this problem ?Cawthon
@Stav Not a clue. I know essentially nothing about windows internals.Sullins
"(including the version in "the same", of course))" => Did you mean "assuming the version is the same"?Episcopalian
R
78

1) is based on the fact that calling a DLL function is always using an extra indirect jump. Today, this is usually negligible. Inside the DLL there is some more overhead on i386 CPU's, because they can't generate position independent code. On amd64, jumps can be relative to the program counter, so this is a huge improvement.

2) This is correct. With optimizations guided by profiling you can usually win about 10-15 percent performance. Now that CPU speed has reached its limits it might be worth doing it.

I would add: (3) the linker can arrange functions in a more cache efficient grouping, so that expensive cache level misses are minimised. It also might especially effect the startup time of applications (based on results i have seen with the Sun C++ compiler)

And don't forget that with DLLs no dead code elimination can be performed. Depending on the language, the DLL code might not be optimal either. Virtual functions are always virtual because the compiler doesn't know whether a client is overwriting it.

For these reasons, in case there is no real need for DLLs, then just use static compilation.

EDIT (to answer the comment, by user underscore)

Here is a good resource about the position independent code problem http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/

As explained x86 does not have them AFAIK for anything else then 15 bit jump ranges and not for unconditional jumps and calls. That's why functions (from generators) having more then 32K have always been a problem and needed embedded trampolines.

But on popular x86 OS like Linux you do not need to care if the .so/DLL file is not generated with the gcc switch -fpic (which enforces the use of the indirect jump tables). Because if you don't, the code is just fixed like a normal linker would relocate it. But while doing this it makes the code segment non shareable and it would need a full mapping of the code from disk into memory and touching it all before it can be used (emptying most of the caches, hitting TLBs) etc. There was a time when this was considered slow.

So you would not have any benefit anymore.

I do not recall what OS (Solaris or FreeBSD) gave me problems with my Unix build system because I just wasn't doing this and wondered why it crashed until I applied -fPIC to gcc.

Rotative answered 3/1, 2010 at 0:19 Comment(3)
I like this answer, because it was the only one to address the points I raised in the question.Editheditha
It would be interesting to have references on those DLL technicalities, and a comparison among different operating systems.Briefcase
Seems fine, but CPU speed has definitely not reached its limits.Playa
B
72

Dynamic linking is the only practical way to meet some license requirements such as the LGPL.

Bacardi answered 3/1, 2010 at 5:1 Comment(3)
As long as the end-user can relink to the LGPL'd code (e.g. because you provide your source code or compiled object files with your software), then static linking is fine. Additionally, if your software is for internal use (i.e. to be used within your organisation only, and not distributed), then you can statically link. This would apply to e.g. server software, where the server is not distributed.Collotype
Don't get it. Could you give me more source (or elaborate more) in order to appreciate what you wrote?Moccasin
@Thorn see the LGPL license section 4.d+e. You either need to distribute in a form that requires the user to do a link, or distribute a shared (dynamic) library.Bacardi
M
47

I agree with the points dnmckee mentions, plus:

  • Statically linked applications might be easier to deploy, since there are fewer or no additional file dependencies (.dll / .so) that might cause problems when they're missing or installed in the wrong place.
Motet answered 3/1, 2010 at 0:16 Comment(1)
It's worth noting that the Go compiler from Google will only statically compile binaries for mainly this reason.Trinette
C
35

One reason to do a statically linked build is to verify that you have full closure for the executable, i.e. that all symbol references are resolved correctly.

As a part of a large system that was being built and tested using continuous integration, the nightly regression tests were run using a statically linked version of the executables. Occasionally, we would see that a symbol would not resolve and the static link would fail even though the dynamically linked executable would link successfully.

This was usually occurring when symbols that were deep seated within the shared libs had a misspelt name and so would not statically link. The dynamic linker does not completely resolve all symbols, irrespective of using depth-first or breadth-first evaluation, so you can finish up with a dynamically linked executable that does not have full closure.

Chevrette answered 3/1, 2010 at 0:39 Comment(0)
H
21

1/ I've been on projects where dynamic linking vs static linking was benchmarked and the difference wasn't determined small enough to switch to dynamic linking (I wasn't part of the test, I just know the conclusion)

2/ Dynamic linking is often associated with PIC (Position Independent Code, code which doesn't need to be modified depending on the address at which it is loaded). Depending on the architecture PIC may bring another slowdown but is needed in order to get benefit of sharing a dynamically linked library between two executable (and even two process of the same executable if the OS use randomization of load address as a security measure). I'm not sure that all OS allow to separate the two concepts, but Solaris and Linux do and ISTR that HP-UX does as well.

3/ I've been on other projects which used dynamic linking for the "easy patch" feature. But this "easy patch" makes the distribution of small fix a little easier and of complicated one a versioning nightmare. We often ended up by having to push everything plus having to track problems at customer site because the wrong version was token.

My conclusion is that I'd used static linking excepted:

  • for things like plugins which depend on dynamic linking

  • when sharing is important (big libraries used by multiple processes at the same time like C/C++ runtime, GUI libraries, ... which often are managed independently and for which the ABI is strictly defined)

If one want to use the "easy patch", I'd argue that the libraries have to be managed like the big libraries above: they must be nearly independent with a defined ABI that must not to be changed by fixes.

Headcloth answered 3/1, 2010 at 10:3 Comment(3)
Some OSes for non-PIC or expensive-PIC processors will prepare dynamic libraries to be loaded at a particular address in memory, and if they can do that, they just map in a copy of the library to every process that links with it. That reduces the overhead of PIC a lot. At least OS X and some Linux distributions do this, I'm not sure about Windows.Wake
Thanks Andrew, I didn't knew that some Linux distributions used this. Do you have a reference I can follow or a key word I can search to learn more? (FWIW I had heard that Windows was doing a variant of this, but Windows is too far out of my zone of competence for me mentioning it).Headcloth
I think the keyword you're looking for is "prelink" - it prepares a library to be loaded quickly at a certain address, to make program startup faster.Disgusting
C
15

Static linking vs Dynamic linking

Static linking is a process in compile time when a linked content is copied into the primary binary and becomes a single binary.

Cons:

  • compile time is longer
  • output binary is bigger

Dynamic linking is a process in runtime when a linked content is loaded. This technic allows to:

  • upgrade linked binary without recompiling a primary one that increase an ABI stability[About]
  • has a single shared copy

Cons:

  • start time is slower(linked content should be copied)
  • linker errors are thrown in runtime

[iOS Static vs Dynamic framework]

Cavuoto answered 10/4, 2020 at 12:36 Comment(0)
R
13

Best example for dynamic linking is, when the library is dependent on the used hardware. In ancient times the C math library was decided to be dynamic, so that each platform can use all processor capabilities to optimize it.

An even better example might be OpenGL. OpenGl is an API that is implemented differently by AMD and NVidia. And you are not able to use an NVidia implementation on an AMD card, because the hardware is different. You cannot link OpenGL statically into your program, because of that. Dynamic linking is used here to let the API be optimized for all platforms.

Roane answered 12/2, 2015 at 1:52 Comment(0)
M
12

It is pretty simple, really. When you make a change in your source code, do you want to wait 10 minutes for it to build or 20 seconds? Twenty seconds is all I can put up with. Beyond that, I either get out the sword or start thinking about how I can use separate compilation and linking to bring it back into the comfort zone.

Mojica answered 3/1, 2010 at 0:42 Comment(1)
I haven't actually benchmarked the difference in compile speeds, but I'd dynamic link if it were significantly faster. Boost does enough bad things to my compile times as it is.Editheditha
U
9

Dynamic linking requires extra time for the OS to find the dynamic library and load it. With static linking, everything is together and it is a one-shot load into memory.

Also, see DLL Hell. This is the scenario where the DLL that the OS loads is not the one that came with your application, or the version that your application expects.

Unwelcome answered 3/1, 2010 at 0:40 Comment(1)
Important to note that there are a range of countermeasures to avoid DLL Hell.Primitivism
E
9

On Unix-like systems, dynamic linking can make life difficult for 'root' to use an application with the shared libraries installed in out-of-the-way locations. This is because the dynamic linker generally won't pay attention to LD_LIBRARY_PATH or its equivalent for processes with root privileges. Sometimes, then, static linking saves the day.

Alternatively, the installation process has to locate the libraries, but that can make it difficult for multiple versions of the software to coexist on the machine.

Eudosia answered 4/1, 2010 at 19:15 Comment(2)
The point about LD_LIBRARY_PATH is not exactly an obstacle for using shared libraries, at least not in GNU/Linux. E.g. if you put the shared libraries in directory ../lib/ relative to the program file, then with GNU tool chain the linker option -rpath $ORIGIN/../lib will specify searching the library from that relative location. You can then easily relocate the application together with all the associated shared libraries. Using this trick, no problem having multiple version of the application and libraries either (assuming they are related, if not you could use symbolic links).Icebox
> for processes with root privileges. I think you are talking about setuid programs run from non-root users - otherwise that makes no sense. And a setuid binary with libraries in non-standard locations is strange - but since only root can install those programs, he can also edit /etc/ld.so.conf for that case.Disgusting
E
7

Another issue not yet discussed is fixing bugs in the library.

With static linking, you not only have to rebuild the library, but will have to relink and redestribute the executable. If the library is just used in one executable, this may not be an issue. But the more executables that need to be relinked and redistributed, the bigger the pain is.

With dynamic linking, you just rebuild and redistribute the dynamic library and you are done.

Electrophorus answered 3/1, 2010 at 8:31 Comment(0)
C
6

Static linking includes the files that the program needs in a single executable file.

Dynamic linking is what you would consider the usual, it makes an executable that still requires DLLs and such to be in the same directory (or the DLLs could be in the system folder).

(DLL = dynamic link library)

Dynamically linked executables are compiled faster and aren't as resource-heavy.

Caliph answered 5/9, 2017 at 12:1 Comment(0)
R
4

There are a vast and increasing number of systems where an extreme level of static linking can have an enormous positive impact on applications and system performance.

I refer to what are often called "embedded systems", many of which are now increasingly using general-purpose operating systems, and these systems are used for everything imaginable.

An extremely common example are devices using GNU/Linux systems using Busybox. I've taken this to the extreme with NetBSD by building a bootable i386 (32-bit) system image that includes both a kernel and its root filesystem, the latter which contains a single static-linked (by crunchgen) binary with hard-links to all programs that itself contains all (well at last count 274) of the standard full-feature system programs (most except the toolchain), and it is less than 20 megabytes in size (and probably runs very comfortably in a system with only 64MB of memory (even with the root filesystem uncompressed and entirely in RAM), though I've been unable to find one so small to test it on).

It has been mentioned in earlier posts that the start-up time of a static-linked binaries is faster (and it can be a lot faster), but that is only part of the picture, especially when all object code is linked into the same file, and even more especially when the operating system supports demand paging of code direct from the executable file. In this ideal scenario the startup time of programs is literally negligible since almost all pages of code will already be in memory and be in use by the shell (and and init any other background processes that might be running), even if the requested program has not ever been run since boot since perhaps only one page of memory need be loaded to fulfill the runtime requirements of the program.

However that's still not the whole story. I also usually build and use the NetBSD operating system installs for my full development systems by static-linking all binaries. Even though this takes a tremendous amount more disk space (~6.6GB total for x86_64 with everything, including toolchain and X11 static-linked) (especially if one keeps full debug symbol tables available for all programs another ~2.5GB), the result still runs faster overall, and for some tasks even uses less memory than a typical dynamic-linked system that purports to share library code pages. Disk is cheap (even fast disk), and memory to cache frequently used disk files is also relatively cheap, but CPU cycles really are not, and paying the ld.so startup cost for every process that starts every time it starts will take hours and hours of CPU cycles away from tasks which require starting many processes, especially when the same programs are used over and over, such as compilers on a development system. Static-linked toolchain programs can reduce whole-OS multi-architecture build times for my systems by hours. I have yet to build the toolchain into my single crunchgen'ed binary, but I suspect when I do there will be more hours of build time saved because of the win for the CPU cache.

Rozellarozelle answered 28/7, 2017 at 22:19 Comment(0)
D
3

static linking gives you only a single exe, inorder to make a change you need to recompile your whole program. Whereas in dynamic linking you need to make change only to the dll and when you run your exe, the changes would be picked up at runtime.Its easier to provide updates and bug fixes by dynamic linking (eg: windows).

Discriminative answered 11/10, 2016 at 1:35 Comment(0)
L
0

Another consideration is the number of object files (translation units) that you actually consume in a library vs the total number available. If a library is built from many object files, but you only use symbols from a few of them, this might be an argument for favoring static linking, since you only link the objects that you use when you static link (typically) and don't normally carry the unused symbols. If you go with a shared lib, that lib contains all translation units and could be much larger than what you want or need.

Lucarne answered 10/9, 2020 at 4:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.