zoukankan      html  css  js  c++  java
  • LinuxDLL加载优化方案

      作者:zhanhailiang 日期:2014-10-26

    linux程序动态库载入流程简单介绍

    linux从程序(program或对象)变成进程(process或进程),简单说来须要经过三步:

    1. fork进程,在内核创建进程相关内核项,载入进程可运行文件;
    2. 查找依赖的.so,逐一载入映射虚拟地址;
    3. 初始化程序变量;

    例如以下例通过strace查看pwd命令运行过程:

    [root@~/wade/codeReview/learningc]# strace pwd
    execve("/bin/pwd", ["pwd"], [/* 24 vars */]) = 0
    brk(0)                                  = 0x1c77000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb011000
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY)      = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=29690, ...}) = 0
    mmap(NULL, 29690, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f06eb009000
    close(3)                                = 0
    open("/lib64/libc.so.6", O_RDONLY)      = 3
    read(3, "177ELF21133>1p3561"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=1921096, ...}) = 0
    mmap(NULL, 3750152, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f06eaa5f000
    mprotect(0x7f06eabe9000, 2097152, PROT_NONE) = 0
    mmap(0x7f06eade9000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x18a000) = 0x7f06eade9000
    mmap(0x7f06eadee000, 18696, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f06eadee000
    close(3)                                = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb008000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb007000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb006000
    arch_prctl(ARCH_SET_FS, 0x7f06eb007700) = 0
    mprotect(0x7f06eade9000, 16384, PROT_READ) = 0
    mprotect(0x7f06eb012000, 4096, PROT_READ) = 0
    munmap(0x7f06eb009000, 29690)           = 0
    brk(0)                                  = 0x1c77000
    brk(0x1c98000)                          = 0x1c98000
    open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=99158576, ...}) = 0
    mmap(NULL, 99158576, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f06e4bce000
    close(3)                                = 0
    getcwd("/root/wade/codeReview/learningc", 4096) = 32
    fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb010000
    write(1, "/root/wade/codeReview/learningc
    ", 32/root/wade/codeReview/learningc
    ) = 32
    close(1)                                = 0
    munmap(0x7f06eb010000, 4096)            = 0
    close(2)                                = 0
    exit_group(0)                           = ?

    由此可见。假设仅仅载入必须的动态库对程序性能有非常重要的意义。

    最佳实践

    1. 程序test.c:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    main () {
        printf ("1");
        exit (0);
    }

    2. 编译test.c

    [root@~/wade/codeReview/learningc/16]# gcc -lm -lpthread -o test test.c 

    3. 通过ldd test命令查看程序执行时须要载入哪些动态库:

    [root@~/wade/codeReview/learningc/16]# ldd test
    	linux-vdso.so.1 =>  (0x00007fff6b5ff000)
    	libm.so.6 => /lib64/libm.so.6 (0x00007f394cefa000)
    	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f394ccdd000)
    	libc.so.6 => /lib64/libc.so.6 (0x00007f394c948000)
    	/lib64/ld-linux-x86-64.so.2 (0x00007f394d187000)

    4. 通过ldd -u test命令查看程序载入了哪些不必要的动态库:

    [root@~/wade/codeReview/learningc/16]# ldd -u test
    Unused direct dependencies:
     
    	/lib64/libm.so.6
    	/lib64/libpthread.so.0

    5. 通过-Wl,–as-needed编译选项仅仅载入必须的动态库:

    [root@~/wade/codeReview/learningc/16]# gcc -Wl,--as-needed -lm -o test test.c 
    [root@~/wade/codeReview/learningc/16]# ldd test
    	linux-vdso.so.1 =>  (0x00007fffdf5ff000)
    	libc.so.6 => /lib64/libc.so.6 (0x00007f5d862cd000)
    	/lib64/ld-linux-x86-64.so.2 (0x00007f5d8666a000)

    參考文章:

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    今日总结
    今日总结
    今日总结
    k8s controller
    深入k8s:Informer使用及其源码分析
    理解 K8S 的设计精髓之 List-Watch机制和Informer模块
    Unix domain socket 简介
    Linux网络编程——端口复用(多个套接字绑定同一个端口)
    DPVS Tutorial
    dpvs route RTF_KNI
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4777968.html
Copyright © 2011-2022 走看看