Fact-checked by Grok 2 weeks ago

Dynamic loading

Dynamic loading is a technique in operating systems whereby individual routines or modules of a are loaded into main only when they are first called during execution, rather than loading the entire at startup. This approach contrasts with static loading, where all is pre-loaded into , and relies on relocatable formats stored on disk to enable retrieval. The mechanism typically involves a relocatable linking loader that checks for a routine's presence in upon ; if absent, it fetches the routine from secondary , adjusts its addresses for the current location, and transfers control to it. No dedicated operating system support is strictly required beyond basic file I/O and relocation capabilities, though many systems provide functions to facilitate the process. Dynamic loading is closely related to but distinct from dynamic linking, which resolves external references at for shared libraries, often using the same to avoid redundant loading across processes. Key advantages include reduced , as unused routines remain unloaded, enabling larger programs to run on resource-constrained systems and improving overall multiprogramming efficiency. It also accelerates program initialization by deferring non-essential loads, though it introduces overhead from repeated loading checks and potential disk I/O delays during execution. In practice, dynamic loading supports modular designs, such as infrequently used error-handling code or optional features, without bloating the resident size. Implementations vary across operating systems but commonly leverage runtime linkers for shared objects. In systems, the dlopen() loads dynamic libraries into a process's and returns a for accessing symbols via dlsym(), allowing explicit control over loading. Similarly, in Windows, the LoadLibrary() enables run-time dynamic linking by mapping DLLs into the process's , with physical memory allocation occurring only . These facilities extend dynamic loading to plugins, drivers, and extensible applications, promoting and easier updates without full program recompilation.

Fundamentals

Definition and Core Concepts

Dynamic loading is a technique in operating systems where executable code, such as routines or modules of a program, is loaded into a running program's only when required during execution, rather than at the program's initial startup. This approach enables efficient use of system resources by deferring the loading of non-essential components until they are explicitly called, avoiding the overhead of loading the entire program image upfront. Core concepts of dynamic loading revolve around relocatable files containing reusable and . These files support relocation, which adjusts addresses to fit the current 's layout using mechanisms like position-independent (PIC). The address space, managed by the (MMU), provides the environment necessary for isolating and mapping these loaded components without interfering with the main program. A relocatable loader, typically part of the program's environment, handles the loading , ensuring and performing necessary relocations. No dedicated operating system support is required beyond basic file I/O capabilities, though many systems provide library functions to facilitate the . The basic workflow of dynamic loading begins with a request from the running program, often triggered by a call to an unloaded routine. The loader first checks if the required routine is already in ; if not, it fetches the routine from secondary storage in relocatable format, adjusts its addresses () to fit the current location, and transfers to it. This integrates the routine seamlessly without needing external resolution unless dynamic linking is involved. Once loaded, the code can be invoked directly, and the loader may it for future use across the program's lifetime. This on-demand mechanism contrasts with static loading by allowing modular extensions without recompilation or restart.

Static vs. Dynamic Loading

Static loading integrates all necessary and dependencies into the file during the or linking phase, resulting in a self-contained that includes copies of required . This approach ensures that the program has no external dependencies, simplifying deployment but leading to larger file sizes as library code is duplicated within each . In contrast, dynamic loading defers the integration of modules until , where the operating system's loader resolves and maps them into as needed, allowing for smaller executables since dependencies are not embedded. A key trade-off lies in memory usage: static loading requires each process to maintain its own duplicate copies of libraries in memory, potentially wasting resources in multi-process environments where the same libraries are used across applications. Dynamic loading, however, enables memory sharing among processes through mechanisms like memory-mapped files, where read-only code is loaded once into physical memory and referenced by multiple executables, reducing overall system memory footprint. This sharing is particularly beneficial in resource-constrained systems, though it introduces complexity in managing shared segments to prevent interference between processes. Examples of static loading often manifest in monolithic executables, such as those using static archives (e.g., .a files), which bundle all components for standalone operation but hinder modular updates. Dynamic loading supports modular architectures, where modules can be updated independently without recompiling dependent programs, facilitating easier maintenance in large software ecosystems. Regarding startup time, static loading typically allows for faster initial program launch since all code is pre-integrated and ready upon execution. Dynamic loading may introduce delays due to runtime loading and relocation, though techniques like pre-loading essential modules can mitigate this.

Dynamic Linking vs. Dynamic Loading

Dynamic linking refers to the process of resolving external references, such as function calls or variables, between a program and its shared libraries at load time or runtime, rather than during compilation. In systems using the Executable and Linkable Format (ELF), this resolution often involves the Procedure Linkage Table (PLT) and Global Offset Table (GOT), where the PLT provides stubs for function calls and the GOT stores addresses that are updated by the dynamic linker to point to the actual library functions. This mechanism allows programs to share code across multiple processes without embedding library code statically. Dynamic loading, in contrast, encompasses the broader of fetching a module file from disk, mapping it into the process's , and performing initial relocations to prepare it for execution. It serves as a superset of dynamic linking, as loading the module is a prerequisite for any subsequent symbol resolution, but dynamic loading can also apply to non-linked modules like plugins that are explicitly loaded via application code. Within dynamic linking, two primary strategies exist: lazy linking and eager linking. Lazy linking defers symbol resolution until the first use of a , typically by having the PLT stub invoke the only when needed, which improves startup performance by avoiding unnecessary resolutions but risks runtime failures if libraries are missing. Eager linking resolves all symbols at load time, enabling early detection of missing dependencies and reducing potential runtime overhead, though it increases initial load time. Both dynamic linking and loading rely on position-independent code (PIC) for shared libraries, which ensures that the library's instructions and data references use relative addressing rather than absolute locations, allowing the library to be loaded at arbitrary memory addresses without modification. This PIC requirement facilitates efficient sharing of libraries across processes while maintaining compatibility with for security.

Historical Development

Origins in Early Operating Systems

Dynamic loading emerged in the mid-1960s as operating systems grappled with limited memory resources and the need for modular program execution in multi-user environments. The project, initiated in 1965 by MIT's Project MAC, Bell Telephone Laboratories, and , pioneered loadable modules through its segmented architecture, allowing procedures and data to be dynamically brought into memory on demand. This approach addressed the constraints of early mainframes by enabling shared code segments to be loaded only when referenced, facilitating efficient resource sharing among multiple users. In , dynamic linking resolved symbolic references at via a -specific linkage section, which translated names to physical addresses without altering shared code. When a first accessed an external , the system assigned it a segment number and instantiated the linkage, supporting fine-grained of pure procedures across users while maintaining . This mechanism, detailed in early design documents, represented a foundational shift toward flexibility, influencing subsequent systems by program loading from compile-time decisions. Concurrently, IBM's OS/360, announced in 1964, introduced overlay loading as a precursor to more advanced dynamic techniques, permitting programmers to structure large programs into hierarchical overlays that sequentially occupied the same memory regions. Macros like CALL and SEGLD enabled the system to load overlay segments asynchronously during execution, conserving core storage in resource-limited mainframes and allowing modular I/O subroutines to be fetched as needed. Dynamic load modules further extended this by supporting reenterable code sharing across tasks, with services such as LOAD and LINK managing entry points and responsibility counts to track usage. The push for dynamic loading was driven by the transition from —where jobs ran sequentially without user interaction—to interactive systems, which demanded on-the-fly module loading to support concurrent users and reduce . , evolving from the (CTSS), exemplified this need by integrating file system access with memory, allowing segments to be paged in dynamically for real-time responsiveness. Key contributions came from researchers, including and , whose work on from 1965 to 1969 laid groundwork for Unix precursors, emphasizing shared libraries and runtime adaptability despite the project's eventual withdrawal in 1969.

Key Milestones and Evolution

Dynamic loading saw significant advancements in the 1980s with the introduction of standardized mechanisms in Unix variants. In Release 4 (SVR4), released in 1989 by AT&T's UNIX System Laboratories, the dlopen() and dlsym() functions were formalized as part of the dynamic linking , enabling programs to load and access symbols from shared libraries at execution time without prior static linking. This innovation, building on earlier concepts from 4.0 in 1988, standardized runtime library loading across System V derivatives, facilitating modular software design and reducing memory redundancy. Parallel developments occurred in BSD Unix during the same decade, evolving toward more efficient dynamic relocation through improved virtual memory management. By the late 1980s and into the 1990s, BSD systems like 4.4BSD (1993) incorporated shared library support, allowing libraries to be mapped into multiple processes. These efforts laid groundwork for portable dynamic loading in academic and research environments. The 1990s marked widespread adoption and refinement, particularly with the transition to the Executable and Linkable Format (ELF) in Linux. Initially using the simpler a.out format, Linux shifted to ELF starting with kernel version 0.99.13 in 1993, becoming the default in Linux 1.2 (1995), which provided superior support for dynamic relocation, position-independent code, and shared library versioning compared to a.out's limitations in handling complex dependencies. This change enabled faster loading and better cross-platform compatibility for dynamic libraries in the growing Linux ecosystem. Concurrently, Microsoft formalized Dynamic Link Libraries (DLLs) in Windows 3.0 (1990), using the New Executable (NE) format to support 16-bit modular extensions, evolving to the Portable Executable (PE) format in Windows NT 3.1 (1993) for 32-bit protected-mode operations and enhanced DLL sharing. Standardization efforts culminated in the 1990s with the inclusion of the dlfcn.h interface in POSIX.1-2001 (ratified in 2001 but based on 1990s X/Open specifications from 1992), which defined portable APIs like dlopen(), dlsym(), and dlclose() for dynamic loading across Unix-like systems, promoting interoperability between BSD, System V, and emerging platforms like Linux. In the 2020s, Linux enhancements focused on performance and isolation, leveraging namespaces to enable more efficient and secure dynamic loading in containerized environments. For instance, user and mount namespaces support isolated dlopen operations, aiding scalability in multi-tenant systems, as seen in kernel updates from Linux 5.10 (2020) onward. These improvements support modern cloud-native applications, emphasizing scalability without compromising security.

Advantages and Challenges

Benefits for Software Design

Dynamic loading significantly enhances in software design by enabling components, such as routines or modules, to be developed, tested, and versioned independently from the main application. This separation reduces the need for full recompilation when updating individual parts, allowing developers to focus on specific functionalities without disrupting the entire . For instance, modules can be modified and redeployed separately, streamlining maintenance and fostering reusable code across projects. In terms of memory efficiency, dynamic loading promotes resource conservation by loading only the required modules into the process's memory , thereby reducing the overall of the application and avoiding allocation for unused . This is particularly beneficial for large programs or resource-constrained systems. When combined with dynamic linking and shared libraries, it further allows to be loaded into physical memory only once and mapped for reuse across multiple processes via mechanisms, minimizing redundant storage, reducing RAM consumption in multi-process environments, and improving system performance through better and (TLB) utilization. On systems running numerous applications that share common libraries, this can lead to substantial savings in compared to static loading. Extensibility is another key advantage, as dynamic loading allows new functionalities, such as plugins or optional modules, to be incorporated at without altering the core application. This addition supports flexible architectures where extension points enable third-party contributions, exemplified by extensions that enhance user interfaces or add specialized tools dynamically. Such mechanisms facilitate incremental and adaptation to evolving requirements while maintaining the stability of the host system. It also accelerates program startup by deferring the loading of non-essential modules until needed, enabling larger programs to run on systems with limited . Backward compatibility benefits from dynamic loading by permitting updates to modules without requiring modifications or relinking of the , ensuring that existing applications continue to function with newer module versions. This is achieved through retrieval and relocation, allowing seamless transitions to patched or enhanced modules while preserving stability. As a result, software ecosystems can evolve more reliably, reducing the risk of breaking changes in deployed systems.

Drawbacks and Security Implications

Dynamic loading introduces performance overhead compared to static loading, primarily due to runtime checks for module presence and potential disk I/O delays when fetching absent routines from secondary storage. For instance, the need to verify if a routine is already in memory and, if not, to load and relocate it adds during execution, especially on systems with slow storage. Additionally, when combined with dynamic linking, symbol resolution and indirect execution mechanisms, such as trampoline code, can increase the number of instructions executed and add pressure on the instruction cache. lookup during loading can incur further delays, especially in systems where unsorted symbol tables necessitate linear searches. Another significant limitation is the potential for runtime failures due to missing or incompatible modules. When loading external modules, the absence of required files at load time can result in unresolved references and program crashes, complicating deployment in diverse environments. In systems using dynamic linking with shared libraries, this can escalate to "dependency hell," where version conflicts or missing libraries lead to failures; for example, in Windows, applications relying on specific dynamic-link libraries (DLLs) can break if subsequent installations overwrite those libraries with incompatible versions, a problem historically prevalent before isolated deployment strategies. Security implications of dynamic loading include the risk of injecting malicious code by loading untrusted modules at runtime. When combined with dynamic linking, this enables attacks like DLL hijacking, where malicious libraries are loaded in place of legitimate ones by exploiting search path vulnerabilities, allowing attackers to plant binaries in trusted directories. Furthermore, regions in multi-process environments can facilitate side-channel attacks, such as inferring sensitive data through timing or contention. Mitigations include enforcing signed binaries, where loaders verify signatures before execution to prevent unsigned or tampered modules from being loaded, as well as secure search paths and policies. Debugging dynamically loaded code presents challenges, particularly in reconstructing stack traces that span module boundaries. Without comprehensive debug symbols from all loaded modules, tools struggle to map addresses across independently compiled components, obscuring error origins and complicating root-cause analysis. This issue is amplified in postmortem scenarios, where dynamic environments require additional notifications for module loads to maintain trace integrity.

Common Applications

Plugin Architectures and Modularity

Dynamic loading enables architectures by allowing applications to discover, load, and integrate external modules at runtime without requiring recompilation or restarts, fostering extensibility and user customization. In image editing software such as , plugins are implemented as dynamically loadable modules using the GimpModule system, which leverages for runtime loading of shared libraries containing extension code for filters, tools, or scripts. Similarly, web browsers like support user extensions through the WebExtensions API, where add-ons are packaged as ZIP files and loaded dynamically upon installation, injecting content scripts and background processes into browser sessions to modify functionality. In , dynamic loading supports by facilitating component-based designs where core systems can import and assemble specialized modules on demand, enhancing and in large-scale applications. This approach allows organizations to extend through pluggable components, such as in service-oriented architectures where dynamic imports enable the of third-party services or updates without disrupting the primary application. For instance, component frameworks in enterprise environments use dynamic loading to manage interdependent modules, ensuring that only required functionalities are activated, which aligns with principles of and high cohesion. A prominent is in media players, where dynamic loading of codecs permits runtime adaptation to diverse file formats without embedding all possible decoders in the core binary. exemplifies this by employing a modular system that dynamically loads codec libraries from the modules directory at startup or on-demand, scanning for available plugins like those for H.264 or decoding based on the media file's requirements. This mechanism ensures efficient resource use, as unused codecs remain unloaded until needed, supporting playback of proprietary or emerging formats through community-contributed modules. Best practices for plugin architectures emphasize defining clear interface contracts to maintain compatibility across versions and prevent integration failures. These contracts typically specify abstract interfaces or APIs that plugins must implement, such as entry points for initialization, execution, and cleanup, allowing the host application to interact with diverse implementations uniformly. Versioning schemes in these contracts, often embedded in the interface definitions, enable forward and backward compatibility, where plugins declare supported host versions during loading to avoid runtime errors. Additionally, employing factory patterns for plugin instantiation and validation checks during discovery ensures robust loading, minimizing security risks from unverified modules.

Runtime Optimization and Resource Management

Dynamic loading facilitates runtime optimization by enabling lazy loading, where modules or libraries are deferred until explicitly needed, thereby reducing the initial of applications. In systems like Unix-based operating systems, lazy loading initializes global offset tables (GOTs) with stub pointers that trigger the dynamic loader only upon first access to a , avoiding the loading of unused segments at startup. This approach not only accelerates program initialization but also conserves , as only accessed modules remain resident; for instance, in scenarios where libraries are infrequently used, overall execution time improves without unnecessary . Similarly, in the (JVM), classes are loaded on demand via the ClassLoader.loadClass method, preserving while minimizing upfront demands and enabling efficient utilization in large-scale applications. Hot-swapping extends these optimizations by allowing the replacement of loaded modules without interrupting execution, supporting zero-downtime updates critical for server environments. In research operating systems like K42, hot-swapping employs a phased —interposing mediators, achieving quiescence through generation counts, transferring , and redirecting via an Object Translation Table (OTT)—to swap object implementations with minimal overhead, primarily limited to pointer costs. This enables dynamic reconfiguration, such as adapting to workload changes or applying patches, without rebooting, thereby maintaining continuous and optimizing . On stock , tools like libDSU facilitate hot-swapping of dynamically linked libraries (e.g., libssl) by updating ELF-format code and data using symbols, reducing windows for uptime-sensitive services without requiring modifications or application restarts. Effective in dynamic loading involves unloading unused libraries to reclaim memory, often integrated with garbage collection mechanisms for automated cleanup. In the JVM, class unloading occurs when the defining class loader becomes unreachable, allowing the garbage collector to free associated metaspace and reduce memory pressure in multi-tasking environments. For native systems, functions like dlclose decrement reference counts and unload shared libraries when no dependencies remain, freeing heap and stack resources while preventing leaks in long-running processes. This integration ensures that transient modules do not persist indefinitely, optimizing memory efficiency particularly in resource-constrained or high-load scenarios. To counter potential delays from on-demand loading, optimization techniques such as preloading common libraries anticipate usage patterns and load them proactively at startup. In AIX environments, environment variables like LDR_PRELOAD force early loading of frequently accessed shared libraries, minimizing symbol resolution during runtime and improving overall performance for applications with predictable dependencies. Combined with lazy binding, preloading balances initial overhead against execution speed, as unresolved symbols are patched only upon access, reducing the full linking burden while ensuring critical modules are readily available.

Implementation in C and C++

Library Loading Mechanisms

In C and C++, dynamic library loading is facilitated through platform-specific APIs that allow programs to load shared object files (e.g., .so on Unix-like systems or .dll on Windows) at runtime, providing access to their symbols without static linking. The POSIX standard defines a set of functions in the <dlfcn.h> header for Unix-like systems, enabling explicit control over loading, symbol resolution, and unloading. These functions return opaque handles representing the loaded modules, which must be managed carefully to avoid resource leaks or invalid accesses. The primary loading function, dlopen(const char *file, int mode), loads the specified library file into the process's and returns a void* to it, or on . The mode parameter controls binding behavior: RTLD_LAZY defers resolution until the first use (performed lazily via relocations), optimizing initial load time, while RTLD_NOW resolves all undefined symbols immediately upon loading, ensuring early detection of missing dependencies but potentially increasing startup . If the file argument is , dlopen returns a to the global object containing all loaded objects. Errors in dlopen are diagnosed using dlerror(void), which returns a human-readable string describing the most recent (or if none occurred since the last call); it is not thread-safe and should be invoked immediately after a failed operation. To unload a , dlclose(void *handle) decrements the reference count of the associated with the ; if the count reaches zero, the system unloads the object, making its unavailable for future . It returns 0 on success or a non-zero value on failure, with details again obtainable via dlerror. is handled by dlsym(void *handle, const char *name), which returns the address (void*) of the named within the loaded object or its dependencies, or if not found (diagnosed via dlerror). The acts as an , not to be dereferenced directly but passed to these functions to scope the search to the specific and its transitive dependencies. On Windows, the equivalent functionality is provided by the Win32 API in <windows.h>, using handles of type HMODULE (which are process-specific and increment a reference count on loading). LoadLibraryA(LPCSTR lpLibFileName) loads the specified DLL into the process and returns an HMODULE handle on success or on failure, with errors retrieved via GetLastError() for extended error codes. Unlike , basic LoadLibraryA performs immediate mapping but relies on the PE loader's default lazy binding for unresolved imports unless overridden with LoadLibraryEx flags. Unloading occurs via FreeLibrary(HMODULE hLibModule), which decrements the reference count and unloads the DLL if it reaches zero, returning a nonzero BOOL on success or zero on failure (check GetLastError). For symbol resolution, GetProcAddress(HMODULE hModule, LPCSTR lpProcName) retrieves the address (FARPROC) of the exported function or variable by name or ordinal, returning on failure with details from GetLastError; the HMODULE handle scopes the lookup to the specific module.

Platform-Specific Procedures

In Linux, dynamic loading of shared libraries in C and C++ is primarily handled through the dlopen function from the <dlfcn.h> header, which loads an ELF-formatted shared object file specified by a path. If the path includes a slash (/), it is treated as an absolute or relative pathname and loaded directly; otherwise, the dynamic linker searches directories in the order of the ELF binary's DT_RPATH tag (if present), the LD_LIBRARY_PATH environment variable (a colon-separated list of directories searched before standard locations), the DT_RUNPATH tag, the ldconfig cache (/etc/ld.so.cache), and finally default paths like /lib and /usr/lib. During loading, the ELF dynamic linker performs relocations by processing tables in the .dynamic section, such as DT_RELA or DT_REL, to resolve symbolic references and adjust addresses based on the load base, enabling position-independent code execution. In BSD systems like FreeBSD, the search order differs: it uses the DT_RPATH of the referencing object (unless DT_RUNPATH exists), the program's DT_RPATH, the LD_LIBRARY_PATH environment variable, the DT_RUNPATH of the referencing object, the hints file managed by ldconfig (typically /var/run/ld.so.hints), and finally /lib and /usr/lib. On Windows, the LoadLibrary or LoadLibraryEx function from <windows.h> loads a DLL into the process address space, with the search order determined by whether safe DLL search mode is enabled (default since Windows XP SP2). If a full path to the .dll is provided, it loads directly from that location; otherwise, for unpackaged applications in safe mode, the system searches the application's folder, the current working directory (if different), the 16-bit system directory, the Windows system directory (%windir%\system32), the Windows directory (%windir%), and finally directories in the PATH environment variable. DLL manifests, embedded in the executable or DLL, can redirect loading to side-by-side assemblies in the WinSxS folder to resolve version conflicts and ensure dependency isolation. macOS employs the dyld dynamic linker for loading Mach-O formatted dynamic libraries (.dylib), often using the POSIX-compatible dlopen function, but with platform-specific extensions for bundles and runpaths. For framework or application bundles, the NSBundle class loads resources and code from a bundle directory at a specified path, integrating with dyld to resolve dependencies within the app's bundle structure. Unlike Linux's LD_LIBRARY_PATH, macOS uses install names with (runpath search path) in the library's LC_ID_DYLIB load command, allowing flexible resolution relative to the executable's location or embedded runpath paths during linking and loading, which avoids hard-coded absolute paths. Cross-platform portability in C and C++ dynamic loading requires addressing differences in path handling, such as Unix-like systems enforcing case-sensitive filenames while Windows treats them as case-insensitive, potentially leading to load failures if paths are not normalized. Error reporting also varies, with Unix systems using dlerror to return descriptive strings and Windows relying on GetLastError for numeric codes that must be formatted via FormatMessage, necessitating conditional or abstraction layers to handle these discrepancies uniformly.

Function Extraction and Unloading

In POSIX-compliant systems, function extraction from a dynamically loaded is performed using the dlsym function, which takes a returned by dlopen and a null-terminated symbol name, returning the address of the symbol as a void* pointer that must be cast to the appropriate type. For example, to retrieve a int myfunc(int), the code would cast the result as (int (*)(int))dlsym([handle](/page/Handle), "myfunc"), ensuring and compatibility with the . On Windows, the equivalent is GetProcAddress, which accepts a module from LoadLibrary and the exported name (or ordinal), returning a FARPROC (void*) that is similarly cast to the target type. In C++, name mangling complicates extraction because compilers encode function signatures into symbol names to support overloading and namespaces, making unmangled names like "myfunc" unavailable via dlsym or GetProcAddress. To resolve this, functions intended for dynamic loading are declared with extern "C" linkage, which disables mangling and preserves C-style names, allowing straightforward symbol lookup while forgoing C++-specific features like overloading for those interfaces. Unloading a shared library in POSIX environments involves calling dlclose on the handle, which decrements the library's reference count; the library is only actually unloaded from memory when the count reaches zero, preventing premature deallocation if multiple handles reference the same object. On Windows, FreeLibrary performs a similar operation by decrementing the module's reference count and unloading only when it hits zero, with the process typically invoking the DLL's DllMain entry point in DLL_PROCESS_DETACH mode for cleanup. Reference counting ensures thread safety and resource sharing across the application, but developers must track handles manually to avoid leaks or invalid calls. Edge cases arise during unloading, particularly with shared data or persistent pointers; if a exports global variables or structures accessed via extracted functions, unloading can create dangling pointers if references remain in the main program, leading to or crashes upon dereference. Static variables within the pose additional risks, as their (if any) are invoked upon unload, potentially freeing resources that external code still holds, such as allocated memory or file handles, which requires explicit or avoidance of cross-library static sharing. Best practices for cleanup emphasize robust error handling: always check the return value of dlclose (non-zero indicates failure, such as invalid handles) and invoke dlerror to retrieve diagnostic messages for or . Similarly, for FreeLibrary on Windows, verify success (non-zero return) and call GetLastError on failure to diagnose issues like dependent modules preventing unload. Prior to unloading, nullify all extracted function pointers and release any library-allocated resources to mitigate dangling references, and consider wrappers for complex scenarios involving multiple loads.

Implementation in Java

Class Loading Architecture

Java's class loading architecture is built around a hierarchical system of class loaders within the (JVM), which enables dynamic loading of classes at while maintaining and . As of Java 9 and later, the hierarchy consists of three primary built-in class loaders: the bootstrap class loader, the platform class loader, and the application (or system) class loader. The bootstrap class loader, implemented in native code by the JVM, loads the core classes from the java.base module and other foundational libraries, serving as the root of the hierarchy. The platform class loader loads classes from the Java platform modules, providing JDK-specific functionality. The application class loader loads classes from the application's or module path, typically specified via the -classpath or -p options or the CLASSPATH . This layered structure ensures that fundamental classes are loaded first, providing a stable foundation for application-specific code. The introduction of the (JPMS) in 9 further refines this architecture by organizing code into modules with explicit dependencies and encapsulation. Class loaders must respect module boundaries during , where a class loader can only access es from other modules if they are exported or opened. This enhances security but requires developers to configure module-info.java files or use JVM flags like --add-exports or --add-opens for dynamic loading scenarios involving or non-exported packages. Prior to Java 9, an extension class loader handled optional extensions from directories like lib/ext, but this was deprecated and removed to favor the modular approach. Central to this architecture is the model, where each class loader delegates the loading request to its parent before attempting to load the class itself, promoting by prioritizing trusted system classes and preventing malicious substitutions. In this model, when a class is requested, the initiating class loader first checks its local cache; if not found, it delegates to the parent (ultimately reaching the bootstrap loader), and only searches its own resources if the parent fails. This delegation enforces through loading constraints, ensuring that classes loaded by different loaders do not violate compatibility rules, such as preventing a class from being loaded twice in conflicting ways. The model also supports user-defined class loaders, which extend java.lang.ClassLoader and can be inserted into the hierarchy to load classes from custom sources like networks or encrypted files, further enabling dynamic behavior without compromising the JVM's integrity, provided module access rules are satisfied. Dynamic class loading is facilitated through methods like Class.forName(String name, boolean initialize, ClassLoader loader) and ClassLoader.loadClass(String name, boolean resolve), which allow classes to be loaded and optionally linked or initialized at runtime based on a binary name. The Class.forName method uses the specified loader (or the caller’s class loader if null) to locate, load, and return a Class object, enabling runtime addition of classes not known at compile time, such as in plugin systems. Similarly, loadClass follows the delegation model to load the class without immediate initialization unless resolve is true. For handling JAR files, particularly from network locations, the URLClassLoader subclass extends this capability by accepting a search path of URLs pointing to JARs or directories, dynamically downloading and loading classes as needed via methods like addURL(URL url). This supports scenarios like remote code loading while respecting the delegation hierarchy, module boundaries, and security contexts. To prevent class conflicts in multi-loader environments, employs namespace isolation, where each loader maintains its own distinct , treating classes with the same fully qualified name as unique if loaded by different loaders. This isolation ensures that, for instance, an application-specific does not override a unintentionally, as the defining loader is part of the 's alongside its name and package. Loading constraints enforced during linkage further resolve potential ambiguities by verifying compatibility across loaders, such as ensuring a loaded by one loader is compatible with references from another. This mechanism is crucial in modular or multi-tenant applications, where separate loaders isolate dependencies and avoid version conflicts.

Dynamic Code Injection Techniques

Dynamic code injection in extends beyond basic class loading by enabling runtime modification and execution of code, often leveraging the Java Virtual Machine's (JVM) reflective and capabilities. This approach is essential for scenarios requiring adaptability, such as framework development or just-in-time optimizations, where code must be altered or executed without recompilation. Techniques like and manipulation allow developers to inspect, invoke, and generate classes dynamically, while hot deployment facilitates seamless updates in production environments. However, these methods must navigate JVM constraints, including classloader hierarchies, encapsulation under JPMS, and , to ensure stability. The Reflection provides a core mechanism for injecting and executing dynamically loaded code by allowing programs to inspect and invoke methods on loaded classes at runtime. Using Class.forName() to load a class followed by getMethod() and Method.invoke(), developers can call arbitrary methods on instances without compile-time knowledge of the class structure. For instance, this enables frameworks like to wire dependencies by reflecting on annotations and invoking setters dynamically. The operates through the java.lang.reflect package, which exposes metadata such as methods, fields, and constructors, facilitating execution even for private or protected members via accessibility overrides. In modular applications, reflection may require JVM flags like --add-opens to access internal module . This technique is particularly useful in plugin systems where loaded classes from external JARs need to be integrated seamlessly into the host application. Bytecode manipulation libraries offer advanced injection by generating or modifying class bytecode directly at runtime, bypassing source code availability. The ASM framework, an open-source bytecode engineering tool, allows visitors to traverse and rewrite class structures, enabling the addition of methods or fields to existing classes before loading them via a custom ClassLoader. Similarly, Javassist simplifies this process with a source-like API for creating classes programmatically, such as defining new methods with CtMethod and compiling them into bytecode for immediate use. These libraries are widely adopted in tools like Hibernate for proxy generation and AspectJ for weaving aspects, supporting runtime enhancements without JVM restarts. By producing valid bytecode compliant with the JVM specification, they ensure injected code executes efficiently, though careful handling is required to avoid verification errors during loading and to comply with module access rules. Hot deployment in application servers like enables class reloading without full JVM restarts, injecting updated code dynamically during operation. Tomcat's StandardHost and components monitor deployed web applications for changes, using background threads to detect modified class files or JARs and trigger redeployment via a dedicated ClassLoader. This process unloads the old loader's classes and loads new ones, preserving session state where possible through configuration attributes like reloadable="true". Such capabilities are critical for development workflows and , reducing in enterprise environments, as demonstrated in Tomcat's manager for on-the-fly updates. However, it relies on isolated classloaders to prevent conflicts, limiting its scope to webapp-specific code, and must account for JPMS restrictions in modular setups. Unloading injected classes poses challenges due to JVM memory management, requiring garbage collection of the associated ClassLoader instances to reclaim resources. In Java versions prior to 8, the Permanent Generation (PermGen) space stored class metadata, and unloading occurred only during full GC cycles when no live references to the ClassLoader or its classes remained, often leading to OutOfMemoryError if PermGen filled. Since Java 8, this was replaced by native Metaspace, which dynamically resizes and unloads classes more reliably under memory pressure, triggered when the ClassLoader becomes unreachable and all class instances are garbage collected. Limitations persist, such as the inability to unload system classes or those loaded by the bootstrap loader, necessitating custom hierarchical ClassLoaders for effective injection-unloading cycles in long-running applications.

Implementation in Other Languages

Python's Dynamic Import System

Python's dynamic import system enables runtime loading of modules, providing flexibility for and architectures. The core mechanism revolves around the importlib module, introduced in Python 3.1 as part of PEP 302, which standardizes dynamic imports and allows customization of the import process. This system abstracts away low-level details, permitting the loading of Python source files (.py), compiled bytecode (.pyc), and extension modules (.so on systems or .pyd on Windows) without requiring static import statements at . The importlib.import_module() function serves as the primary interface for dynamic imports, taking a module name as a string and returning the loaded object. It leverages a of loaders to handle different module types: SourceFileLoader for .py files, SourcelessFileLoader for .pyc files, and ExtensionFileLoader for C extensions, ensuring that the appropriate loader is selected based on the module's location and format. For instance, when importing a module like "example.module", import_module resolves the through the import machinery and executes the module's if necessary. This approach supports , where modules are only instantiated when explicitly requested, optimizing memory usage in large applications. Dynamic path manipulation enhances the system's adaptability by allowing runtime modifications to the search path via sys.path, a list of directories where searches for . Developers can insert custom paths—such as temporary directories or folders—using sys.path.insert(0, '/path/to/plugins'), enabling the discovery of from non-standard locations without altering the PYTHONPATH . This is particularly useful in scenarios like web frameworks or that load user-defined extensions . However, care must be taken to avoid path conflicts or risks from untrusted directories. For iterative development and hot-reloading, importlib.reload() facilitates reloading already imported modules without restarting the interpreter. This function re-executes the module's code, updating its while preserving references to the original module object, which is essential for and environments. It handles pure modules effectively but may not fully reload C extensions due to their compiled nature, potentially requiring additional safeguards for stateful code. Python also supports loading C extensions dynamically through high-level interfaces like ctypes, which provides a foreign function library for calling functions in shared libraries without writing wrappers. Using ctypes.CDLL() or ctypes.WinDLL(), developers can load .so/.pyd files at and access their symbols, bridging Python's interpreted environment to native dynamic loading mechanisms like dlopen on Unix or LoadLibrary on Windows. For deeper integration, the Python C API allows embedding dynamic loading via functions like PyImport_ImportModule(), which invokes the import machinery from C code. This combination enables performance-critical extensions to be loaded conditionally, such as in scientific computing libraries like .

JavaScript's Dynamic Imports

JavaScript's dynamic imports, standardized in ECMAScript 2020, allow developers to load modules asynchronously at runtime using the import() expression, which functions like a promise-returning call rather than a static declaration. This mechanism supports conditional or on-demand loading, making it ideal for optimizing resource use in both browser and Node.js environments by deferring module execution until needed. Unlike static import statements, which must be declared at the top level and resolved during parsing, import() enables dynamic specifier evaluation, such as constructing paths based on runtime conditions. The expression returns a Promise that resolves to a module namespace object containing all exports, or rejects if loading or evaluation fails, such as due to network errors or syntax issues. For instance, demonstrates conditional loading:
javascript
if ([condition](/page/Condition)) {
  [import](/page/Import)('./optional-[module](/page/Module).js')
    .then([module](/page/Module) => {
      [module](/page/Module).initialize();
    })
    .catch(error => {
      console.error('Module load failed:', error);
    });
}
In contexts like <script type="[module](/page/Module)"> in browsers or ES in , import() integrates with top-level await, simplifying asynchronous without explicit .then() handling:
javascript
const [module](/page/Module) = await [import](/page/Import)('./[module](/page/Module).js');
[module](/page/Module).[default](/page/Default)();
This feature enhances compatibility with async/await patterns and is supported across modern JavaScript runtimes. In , the require() function provides an alternative for dynamic loading in modules, operating synchronously by default to import other modules, files, or native addons from the or node_modules. It resolves paths using algorithms that prioritize local files, core modules, and package directories, returning the module.exports object immediately upon loading. To optimize performance, caches loaded modules in require.cache, keyed by their resolved filename, ensuring subsequent calls to require() reuse the same instance without re-execution—this caching prevents redundant work but can lead to shared state across requires. While require() lacks native asynchrony, developers can wrap it in promises for async behavior, though the ECMAScript import() is preferred for true asynchronous loading in ES modules. A key distinction from environments lies in resolution and execution: rely on URL-based fetching and enforce strict ES module syntax without direct access, whereas require() integrates with the local and supports extensions like .json or .node for native bindings. For example:
javascript
const fs = require('node:fs');  // Synchronous load from core module
const config = require('./config.json');  // Loads and parses [JSON](/page/JSON) synchronously
This synchronous nature suits but contrasts with the inherently async import() in web contexts, where network latency necessitates promise-based handling. Dynamic imports facilitate bundle splitting in web applications, particularly with tools like , which analyze import() calls as split points to generate separate chunks for on-demand loading, thereby reducing the initial bundle size and improving page load performance. In configurations, these dynamic loads create asynchronous bundles (e.g., chunk-vendors.js) that are fetched only when the import executes, enabling of features like components or libraries. This approach prioritizes critical code in the main bundle while deferring others, aligning with runtime optimization by minimizing upfront resource demands in browser environments. For example, might split a large library like :
javascript
// In a component file
async function renderPage() {
  const { default: _ } = await [import](/page/Import)('lodash');  // Triggers separate chunk load
  const content = _.join(['Dynamic', 'Content'], ' ');
  document.getElementById('app').innerHTML = content;
}
Such splitting can reduce initial payloads by hundreds of kilobytes, as seen in builds where non-essential modules form distinct 500+ KiB chunks loaded via network requests. Unloading dynamically loaded modules in JavaScript environments presents significant limitations, primarily due to the V8 engine's design in Node.js and browsers, which lacks native support for evicting compiled code or fully releasing module resources. In Node.js CommonJS, manual unloading is possible by deleting the module's entry from require.cache using delete require.cache[require.resolve('./module.js')], forcing subsequent require() calls to reload the module afresh; however, this only affects JavaScript modules and does not apply to native addons, which error on reload attempts. Even after cache deletion, V8's garbage collector may retain memory if lingering references (e.g., globals, event listeners, or circular dependencies) prevent full deallocation, potentially leading to memory leaks in long-running processes. In browser ES modules, no standard unloading API exists, leaving loaded modules in memory until page refresh, as the runtime prioritizes stability over dynamic eviction. Developers must carefully manage references to enable garbage collection, but complete unloading remains unreliable without restarting the context.

Platforms and Environments Without Native Support

Embedded Systems Constraints

Embedded systems often impose severe constraints on dynamic loading due to their limited () and (), which typically range from a few kilobytes to megabytes. These limitations make runtime symbol resolution and library loading challenging, often leading to a preference for static linking to minimize overhead and ensure a small runtime footprint. Additionally, requirements in these environments demand deterministic execution times, where delays from dynamic linking—such as symbol lookup or —can complicate meeting strict timing deadlines. Microcontrollers such as those based on AVR architecture and series predominantly rely on static linking, as their bare-metal or minimal OS environments lack units (MMUs), complicating efficient dynamic code execution. For instance, AVR devices, commonly used in low-power applications, compile all dependencies into a single image to fit within constrained and , avoiding the need for loaders or dynamic allocators. Similarly, processors, prevalent in and industrial controls, favor static builds to maintain low latency, though dynamic loading is possible in some cases using bootloaders and , albeit with added complexity. Traditionally, safety-critical applications, such as automotive electronic control units (ECUs), have prioritized predictability over flexibility by favoring static linking to ensure deterministic behavior and meet certification standards like . In these domains, runtime variability from loading modules can risk timing unpredictability, potentially leading to hazardous failures in systems like engine management or braking controls. However, recent research has developed techniques for composable and predictable dynamic loading that maintain isolation and bounded execution times, enabling flexibility without compromising safety. Some operating systems (RTOS) provide partial support for pseudo-dynamic loading through overlay managers, which swap predefined code segments in and out of memory without full symbol resolution. For example, can incorporate overlay mechanisms via customized linker scripts, allowing segments to be loaded from into during operation, simulating dynamic behavior while adhering to resource limits. This approach, often used in resource-constrained ports, enables modular updates but remains limited compared to native dynamic systems in general-purpose computing. Recent advancements as of 2025 have further addressed these constraints, with techniques like compilation and runtimes enabling dynamic code execution in systems while respecting resource limits and needs.

Alternatives in Restricted Environments

In environments where dynamic loading is infeasible due to resource limitations or security restrictions, such as memory-constrained systems, developers employ static techniques to achieve similar modularity. Static plugins enable compile-time selection of code modules, allowing conditional inclusion without runtime overhead. macros facilitate this by defining symbols that control conditional , where specific code paths or functions are included or excluded based on build configurations, effectively simulating plugin selection for different or features in . Linker scripts complement this approach by specifying how object files are organized and placed in memory, enabling the linker to assemble only the required modules into a monolithic , which reduces binary size and avoids dynamic resolution complexities. For instance, in projects, macros can toggle peripheral drivers at build time, while linker scripts map them to fixed addresses, providing a form of extensibility without native dynamic . Interpreted overlays offer pseudo-dynamic behavior through lightweight scripting engines embedded within the host application. These engines interpret scripts at runtime, allowing code modifications without recompiling the core system, thus approximating dynamic loading in resource-limited settings. , designed for embeddability with a minimal of around 200 KB, exemplifies this by integrating as a library in C-based embedded applications, where scripts handle configurable logic like user interfaces or algorithms. In practice, Lua's stack-based enables safe execution of overlays that interact with host APIs via bindings, supporting hot-reload of scripts for tasks like game logic or device control in systems lacking native loaders. Firmware updates via over-the-air () mechanisms simulate hot-swapping by replacing entire images or without full system restarts, providing a for code evolution in deployed devices. processes typically involve downloading a new binary to a reserved sector, validating it, and switching execution to the updated upon , which mimics dynamic updates while maintaining system integrity. In automotive and contexts, this approach uses dual-bank storage to ensure capability, allowing seamless feature additions or bug fixes without true runtime loading. For example, microcontrollers like those from employ protocols to orchestrate these swaps, achieving near-hot-swap reliability with minimal . Virtualization through hypervisors provides for dynamic components on constrained hosts by partitioning the into virtual machines (), enabling modular execution without direct access. hypervisors, such as those based on microkernels like seL4, run a minimal layer to host multiple isolated guests, where dynamic elements can be loaded within while remains static and secure. This technique supports mixed-criticality s by confining potentially dynamic or third-party code to guest partitions, leveraging extensions like TrustZone for efficient in resource-scarce environments. In safety-critical applications, hypervisors like XtratuM or INTEGRITY-178 ensure temporal and spatial separation, allowing updates to non-critical components without affecting the core .

References

  1. [1]
    Operating Systems: Main Memory
    4 Dynamic Loading. Rather than loading an entire program into memory at once, dynamic loading loads up each routine as it is called. The advantage is that ...8.4 Segmentation · 8.5 Paging · 8.5. 1 Basic Method
  2. [2]
    Anatomy of Linux dynamic libraries - IBM Developer
    Aug 20, 2008 · With dynamic loading, a program can load a specific library (unless already loaded), and then call a particular function within that library. ( ...
  3. [3]
    dlopen
    The dlopen() function shall make the symbols (function identifiers and data object identifiers) in the executable object file specified by file available to ...Missing: man | Show results with:man
  4. [4]
    Using Run-Time Dynamic Linking - Win32 apps - Microsoft Learn
    Jun 16, 2022 · You can use the same DLL in both load-time and run-time dynamic linking. The following example uses the LoadLibrary function to get a handle to the Myputs DLL.Missing: docs | Show results with:docs
  5. [5]
    [PDF] Memory Management
    Dynamic Loading. ▫. Routine is not loaded until it is called. ▫. Better ... OS can help by providing libraries to implement dynamic loading. Page 14. 8.14.
  6. [6]
    [PDF] The inside story on shared libraries and dynamic loading
    Sep 2, 2025 · Instead, the operating system loads and executes the dynamic linker (usually called ld.so), which then scans the list of library names embedded ...
  7. [7]
    [PDF] Operating Systems Lecture 20: Program linking and loading
    CS5460/6460: Operating Systems. Lecture 20: Program linking and loading ... ○ Static and shared libraries. ○ Dynamic linking and loading. ○ Position ...
  8. [8]
    Dynamic Linking vs. Dynamic Loading - Baeldung
    Mar 18, 2024 · Dynamic loading is the technique through which a computer program at runtime load a library into memory, retrieve the variable and function addresses, executes ...
  9. [9]
    Executable and Linkable Format 101 Part 4: Dynamic Linking - Intezer
    Jun 25, 2019 · At load-time, the dynamic linker fills every GOT entry with the address pointing to the second instruction of the respective PLT entry.
  10. [10]
    A look at dynamic linking - LWN.net
    Feb 13, 2024 · The dynamic linker initially fills the PLT's GOT with the address of a function from the dynamic linker itself. This function consults the link ...
  11. [11]
    linker - difference between dynamic loading and dynamic linking?
    Apr 7, 2012 · Dynamic loading is a mechanism by which a computer program can, at run time, load a library (or other binary) into memory, retrieve the addresses of functions ...
  12. [12]
    Position Independent Code (PIC) in shared libraries
    Nov 3, 2011 · This article explained what position independent code is, and how it helps create shared libraries with shareable read-only text sections.
  13. [13]
    Position-Independent Code - Linker and Libraries Guide
    Position-independent code can be loaded in any region in memory, and hence satisfies the requirements of shared objects for x64. This situation differs from ...
  14. [14]
    History - Multics
    Jul 31, 2025 · Multics (Multiplexed Information and Computing Service) is a mainframe time-sharing operating system begun in 1965 and used until 2000.Missing: loadable | Show results with:loadable
  15. [15]
    [PDF] Virtual Memory, Processes, and Sharing in MULTICS - andrew.cmu.ed
    The means by which users may share procedures and data is discussed and the mechanism by which symbolic references are dynamically transformed into virtual ...
  16. [16]
    [PDF] Multics: Dynamic Linking
    Two ways to refer to data: (segment number, offset) and (file name, offset); segment is stored on disk or memory. ▫. Kind of like “mmap” for all data.
  17. [17]
    [PDF] Systems Reference Library IBM System/3S0 Operating System ...
    LOAD MODULE STRUCTURE TYPES. Each load module used during a job step can be designed in one of three load module structures: simple, planned overlay, or dynamic ...
  18. [18]
    Evolution of the Unix Time-sharing System - Nokia
    We were among the last Bell Laboratories holdouts actually working on Multics, so we still felt some sort of stake in its success. More important, the ...
  19. [19]
    dlopen(3) - Linux manual page - man7.org
    dlopen() The function dlopen() loads the dynamic shared object (shared library) file named by the null-terminated string path and returns an opaque "handle" for ...
  20. [20]
    A way out for a.out - LWN.net
    Mar 24, 2022 · Still, Linux used a.out for some time, until support for the newfangled ELF format was first added to the 0.99.13 development kernel in 1993.
  21. [21]
    PE Format - Win32 apps - Microsoft Learn
    Jul 14, 2025 · This document specifies the structure of executable (image) files and object files under the Microsoft Windows family of operating systems.Missing: history | Show results with:history
  22. [22]
    [PDF] How To Write Shared Libraries - Dartmouth Computer Science
    Dec 10, 2011 · This is done by loading the code into physical memory only once and reusing it in multiple processes via virtual memory. Libraries of this kind ...
  23. [23]
    Linking and Shared Libraries - Cornell: Computer Science
    Shared libraries and DSOs allow efficient memory use on a machine running many different programs that share code, inproving cache and TLB performance overall.
  24. [24]
    [PDF] Router Plugins A Software Architecture for Next Generation Routers
    Extensibility: New plugins can be dynamically loaded at run time. • Flexibility: Instances of plugins can be created, config- ured, and bound to specific ...
  25. [25]
    On Plug-ins and Extensible Architectures - ACM Queue
    Mar 18, 2005 · This article identifies some of the concepts around the foundation of pure plug-in architectures and how they affect various stakeholders when taking a plug-in ...
  26. [26]
    [PDF] Dynamic Sharing and Backward Compatibility on 64-Bit Machines
    Apr 23, 1992 · It is used to save space in the file system and in physical memory, and to permit updating of libraries without recompiling all the programs ...
  27. [27]
    Symbol Table Section - Oracle® Solaris 11.3 Linkers and Libraries ...
    Symbols are not sorted by address, which forces an expensive linear search of the entire table. More than one symbol can refer to a given address. Although ...<|separator|>
  28. [28]
    Avoiding DLL Hell: Introducing Application Metadata in the Microsoft ...
    Oct 24, 2019 · This is one of the reasons why innocent people end up in DLL Hell when a shared component is updated or deleted. . NET, with its use of ...
  29. [29]
    Dll hell: software dependencies, failure, and the maintenance of ...
    Software applications often failed because they required specific dynamic-link libraries (DLLs), which other applications may have overwritten with their own ...
  30. [30]
    Secure loading of libraries to prevent DLL preloading attacks
    These attacks are known as “DLL preloading attacks” and are common to all operating systems that support dynamically loading shared DLL libraries.
  31. [31]
    [PDF] Dynamic Linking in Trusted Execution Environments in RISC-V
    May 18, 2022 · However, sharing libraries across enclaves also creates a security risk due to side-channel attacks on shared memory. One such well studied ...
  32. [32]
    Exploit protection reference - Microsoft Defender for Endpoint
    Mar 25, 2025 · The technique of DLL planting abuses the loader's search mechanism to inject malicious code, which can be used to get malicious code running ...
  33. [33]
    Postmortem Debugging in Dynamic Environments - ACM Queue
    Oct 3, 2011 · Postmortem debugging technology has been developed and used in many different systems, including all major consumer and enterprise operating systems.
  34. [34]
    Windows XP: Escape from DLL Hell with Custom Debugging and ...
    Oct 22, 2019 · The Win32 debugging API provides a solution to this problem: when you debug an application, you are notified whenever a DLL gets loaded and ...
  35. [35]
    Practical Guide to Plugin Architecture in C++ - eInfochips
    Jun 23, 2025 · Plugin architecture uses interfaces as contracts, dynamic loading to load plugins at runtime, and factory functions to create plugin instances.<|control11|><|separator|>
  36. [36]
  37. [37]
  38. [38]
    Plugin Architecture With Forward & Backward Compatibility
    Mar 15, 2013 · First, Your PluginAPI (containing the interfaces) should be a separate DLL to your main application. Your main application will reference the ...How To Create a Flexible Plug-In Architecture? [closed]How to design extensible software (plugin architecture)? [closed]More results from stackoverflow.comMissing: contracts | Show results with:contracts
  39. [39]
    It's All In The Libs – Building A Plugin System Using Dynamic Loading
    Jul 12, 2018 · Dynamic loading allows loading libraries at runtime, making them optional. This is used to build plugin systems, extending program ...
  40. [40]
    [PDF] Linking Programs in a Single Address Space - USENIX
    Linking and loading are the final steps in preparing a program for execution. This paper assesses issues con- cerning dynamic and static linking in ...
  41. [41]
    Dynamic class loading in the Java virtual machine
    form of dynamic loading and linking, the Java platform is the only system we know of that incorporates all of the following features: 1. Lazy loading.
  42. [42]
    [PDF] Module Hot-Swapping for Dynamic Update and Reconfiguration in ...
    Hot-swapping in K42 allows objects to be changed on-the-fly, enabling dynamic reconfiguration and transparent switching to another implementation while running.
  43. [43]
    libDSU: towards hot-swapping dynamically linked libraries on stock ...
    Oct 20, 2016 · We discuss that security critical updates also affect data and present an approach for dynamically updating code and data in stock dynamically ...Missing: zero- | Show results with:zero-
  44. [44]
    Optimized memory management for class metadata in a JVM
    Aug 24, 2011 · Metaspace-based management of class metadata also extends well to multi-tasking implementations of the JVM. It enables tasks to unload classes ...
  45. [45]
  46. [46]
    dlopen
    ### Summary of dlopen from https://pubs.opengroup.org/onlinepubs/000095399/functions/dlopen.html
  47. [47]
    dlerror
    ### Summary of dlerror from https://pubs.opengroup.org/onlinepubs/000095399/functions/dlerror.html
  48. [48]
    dlclose
    The dlclose() function shall inform the system that the object referenced by a handle returned from a previous dlopen() invocation is no longer needed by the ...
  49. [49]
    dlsym
    ### Summary of dlsym from https://pubs.opengroup.org/onlinepubs/000095399/functions/dlsym.html
  50. [50]
    LoadLibraryA function (libloaderapi.h) - Win32 apps - Microsoft Learn
    Feb 8, 2023 · LoadLibrary can be used to load a library module into the address space of the process and return a handle that can be used in GetProcAddress to ...Syntax · Parameters
  51. [51]
    FreeLibrary function (libloaderapi.h) - Win32 apps | Microsoft Learn
    Oct 12, 2021 · A handle to the loaded library module. The LoadLibrary, LoadLibraryEx, GetModuleHandle, or GetModuleHandleEx function returns this handle.Missing: GetProcAddress | Show results with:GetProcAddress
  52. [52]
    GetProcAddress function (libloaderapi.h) - Win32 - Microsoft Learn
    Feb 6, 2024 · Retrieves the address of an exported function (also known as a procedure) or variable from the specified dynamic-link library (DLL).
  53. [53]
    ld.so(8) - Linux manual page - man7.org
    LD_LIBRARY_PATH A list of directories in which to search for ELF libraries at execution time. The items in the list are separated by either colons or semicolons ...
  54. [54]
    [PDF] Tool Interface Standard (TIS) Executable and Linking Format (ELF ...
    An ELF header resides at the beginning and holds a "road map'' describing the file's organization. Sections hold the bulk of object file information for the ...
  55. [55]
    Dynamic-link library search order - Win32 apps | Microsoft Learn
    Feb 8, 2023 · The standard DLL search order used by the system depends on whether or not safe DLL search mode is enabled.Factors That Affect... · Search Order For Packaged... · Search Order For Unpackaged...
  56. [56]
    Mac OS X Manual Page For dlopen(3) - Apple Developer
    This document is a Mac OS X manual page. Manual pages are a command-line technology for providing documentation. You can view these manual pages locally ...
  57. [57]
    Apple Developer Documentation
    **Summary of NSBundle Usage for Loading Bundles on macOS:**
  58. [58]
    Overview of Dynamic Libraries - Apple Developer
    Jul 23, 2012 · Explains how to design, implement, and use dynamic libraries.
  59. [59]
    dlsym(3) - Linux manual page - man7.org
    History The dlsym() function is part of the dlopen API, derived from SunOS. That system does not have dlvsym().Missing: V | Show results with:V
  60. [60]
    dlsym
    The following example shows how dlopen() and dlsym() can be used to access either function or data objects. For simplicity, error checking has been omitted.
  61. [61]
    Dynamic Class Loading for C++ on Linux
    May 1, 2000 · The problem is that C++ function names are mangled to support function overloading, so the maker function may have a different name in the ...<|separator|>
  62. [62]
    Dynamic-Link Library Best Practices - Win32 apps | Microsoft Learn
    May 12, 2023 · This document provides guidelines for DLL developers to help in building more robust, portable, and extensible DLLs.Missing: dlclose | Show results with:dlclose
  63. [63]
    Dynamic-Link Library Entry-Point Function - Win32 apps
    Jan 7, 2021 · The DLL is unloaded when the process terminates or calls the FreeLibrary function and the reference count becomes zero. If the process ...
  64. [64]
    Understanding Extension Class Loading (The Java™ Tutorials ...
    The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a "parent" class loader. When loading a class, a ...Missing: JVM | Show results with:JVM
  65. [65]
    Chapter 5. Loading, Linking, and Initializing
    The Java Virtual Machine starts up by creating an initial class or interface using the bootstrap class loader (§5.3.1) or a user-defined class loader (§5.3.2).Missing: architecture | Show results with:architecture
  66. [66]
    ClassLoader (Java Platform SE 8 )
    ### Summary of ClassLoader in Java SE 8
  67. [67]
  68. [68]
    Class (Java Platform SE 8 )
    ### Summary: How Class.forName Enables Dynamic Class Loading at Runtime
  69. [69]
  70. [70]
    URLClassLoader (Java Platform SE 8 )
    ### Summary of URLClassLoader's Role in Dynamic Loading of JAR Files from Network Locations
  71. [71]
    Invoking Methods - The Java™ Tutorials
    This reflection Java tutorial describes using reflection for accessing and manipulating classes, fields, methods, and constructors.
  72. [72]
    Call Methods at Runtime Using Java Reflection | Baeldung
    Jan 8, 2024 · Overview. In this short article, we'll take a quick look at how to invoke methods at runtime using the Java Reflection API.
  73. [73]
    ASM
    ASM is an all purpose Java bytecode manipulation and analysis framework. It can be used to modify existing classes or to dynamically generate classes.Versions · Documentation · License · FAQ
  74. [74]
    Javassist by jboss-javassist
    It is a class library for editing bytecodes in Java; it enables Java programs to define a new class at runtime and to modify a class file when the JVM loads it.
  75. [75]
    A Guide to Java Bytecode Manipulation with ASM | Baeldung
    Jan 8, 2024 · In this article, we'll look at how to use the ASM library for manipulating an existing Java class by adding fields, adding methods, and changing ...Missing: Javassist | Show results with:Javassist
  76. [76]
  77. [77]
    Tomcat Web Application Manager How To
    Mar 19, 2024 · Manage your web applications without having to shut down and restart Tomcat. This document is for the HTML web interface to the web application manager.Introduction · Applications · Deploy
  78. [78]
    10 Other Considerations - Oracle Help Center
    Java classes are unloaded as a result of garbage collection, and garbage collections may be induced to unload classes and deallocate class metadata. When ...
  79. [79]
    Where Has the Java PermGen Gone? - InfoQ
    Jul 7, 2014 · Once this watermark is hit, a full garbage collection is triggered to unload classes (when their classloaders are no longer alive) and the high ...
  80. [80]
    import() - JavaScript - MDN Web Docs - Mozilla
    Nov 3, 2025 · The import() syntax, commonly called dynamic import, is a function-like expression that allows loading an ECMAScript module asynchronously and dynamicallyDescription · Module Namespace Object · Examples
  81. [81]
  82. [82]
    import - JavaScript - MDN Web Docs - Mozilla
    Nov 2, 2025 · There is also a function-like dynamic import() , which does not require scripts of type="module" . In this article. Syntax; Description ...Import() · Import attributes · Import.meta · Export
  83. [83]
    CommonJS modules | Node.js v25.1.0 Documentation
    The semantics of the Node.js require() function were designed to be general enough to support reasonable directory structures. Package manager programs such as ...Node:module API · ECMAScript modules · OS
  84. [84]
  85. [85]
  86. [86]
  87. [87]
    Code Splitting - webpack
    Dynamic Imports: Split code via inline function calls within modules. Entry Points. This is by far the easiest and most intuitive way to split code. However ...
  88. [88]
  89. [89]
  90. [90]
    C++ addons | Node.js v25.1.0 Documentation
    The require() function can load addons as ordinary Node.js modules. Addons provide an interface between JavaScript and C/C++ libraries. There are three ...
  91. [91]
    [PDF] Dynamic Loading in an Application Specific Embedded Operating ...
    Embedded systems however have constraints, such as limited memory and real-time requirements, that prevent many dynamically configurable operating systems ...Missing: ROM | Show results with:ROM
  92. [92]
    Position-Independent Code with GCC for ARM Cortex-M
    Jun 5, 2021 · Position-independent code (PIC) allows code to run anywhere in the address space, enabling loading and execution at different memory locations.
  93. [93]
    static versus shared libraries in small embedded systems using C ...
    Jul 29, 2012 · If I have made a static library for a .c files which has multiple API's and I am statically linking it with main file and in main file only one ...Missing: AVR | Show results with:AVR
  94. [94]
    Problem when dynamically loading code (Cortex-M4) - Support forums
    Jul 1, 2020 · Hello everyone. I want to implement dynamic loading of functions in RAM for a Cortex-M4. It partially works but with a small hack which is not ...
  95. [95]
    [PDF] Composable and predictable dynamic loading for time-critical ...
    Nov 1, 2015 · Time-critical systems for instance in avionics, have strict safety, real-time and fault tolerance constraints. To ensure these con- straints ...
  96. [96]
    Composable and predictable dynamic loading for time-critical ...
    Hence the dynamic loading in time-critical systems should be predictable. We define loading as predictable, if a bound on the loading time can be computed at ...Missing: avoid | Show results with:avoid
  97. [97]
    Dynamic Code Loading Support - FreeRTOS Community Forums
    Jul 14, 2016 · Can anyone please suggest some solution to this issue and the feasibility of Dynamic code loading Feature. Note: As we are using an ARM Cortex ...
  98. [98]
    Overlay Support for Library Archive(static library, .a file) on GNU-GCC
    Aug 17, 2016 · I was working on customizing the linker script for including overlay mechanism. I have succeeded in creating a sample project which uses overlay ...
  99. [99]
    [PDF] The C Preprocessor - GCC, the GNU Compiler Collection
    The C preprocessor, often known as cpp, is a macro processor that is used automatically by the C compiler to transform your program before compilation.
  100. [100]
    [PDF] A Primer on Linker Scripts and Command Files - TI E2E
    Linker scripts (or command files) are text files that tell the linker how to combine code and data, and where to place it in memory.<|separator|>
  101. [101]
    A Look at the Design of Lua - Communications of the ACM
    Nov 1, 2018 · What sets Lua apart from other scripting languages is its particular set of goals: simplicity, small size, portability, and embeddability. The ...Missing: engine alternatives
  102. [102]
    Passing a Language through the Eye of a Needle - ACM Queue
    May 12, 2011 · In this article we discuss how embeddability can impact the design of a language, and in particular how it impacted the design of Lua from day one.Missing: alternatives | Show results with:alternatives
  103. [103]
    Over-the-Air (OTA) Updates in Embedded Microcontroller Applications
    In this article, we will describe several different software designs for OTA updates and discuss their trade-offs.
  104. [104]
    Virtualization Technology for Dependable Embedded Systems
    Sep 13, 2025 · This paper describes a new hypervisor built to run Linux in a virtual machine. This hypervisor is built inside Anaxagoros, a real-time ...