• Windows 程序启动性能优化(先载入EXE,后载入DLL,只取有限的代码载入内存,将CPU的IP指向程序的入口点)


    一、重定位
    链接时重定位:
    目标文件一般由多个节组成,编译器在编译每个目标文件时一般都是从0地址开始生成代码。当多个代码节合成一个代码段时,需要根据其在最终代码段中的位置做出调整。同时,链接器需要对已经解析的符号分配运行时地址。这个过程就是重定位。

    加载时重定位:
    程序中可能调用了DLL,由于EXE是最先被加载的,所以一般都能加载到其想要的内存地址上;而DLL的加载一般在EXE之后,就需要对DLL中的地址进行重定位了。

    二、程序的启动过程
    WIN32程序启动过程包括:

    (1)操作系统把程序加载到内存,并建立相应的运行环境
    (2)应用程序自身的初始化过程

    备注:应用程序必须符合PE格式,主要包含:data(数据段),.text(代码段)。数据和代码加载到内存中后(内存中,应用程序的代码表现为一系列有序的指令集),CPU从程序入口处按顺序取出每一条指令并执行。

    加载器:操作系统加载器的任务是,把磁盘中可执行程序的物理文件读入内存,并转换成程序在内存中的表示。

    三、编译链接和启动
    编译链接:

    (1)预编译展开宏
    (2)为每个.cxx文件生成一个.obj文件,目标文件至少包含数据段和代码段;目标文件还包含一个符号表,用于记录自己引用          的符号,以及提供给外部引用的符号。
    (3)编译器合成这些目标文件成一个库文件(.lib),同时解析可以找到的符号引用
    (4)链接器把目标库文件和所有需要引用的静态、动态库进行链接,生成最终的可执行文件。(首先需要把依赖的静态库合            成到可执行文件中,其次要保证依赖的动态库文件的符号都存在)可执行文件的符号表只需要记录导入符号表。


    启动:
    不依赖DLL的程序:

    (1)操作系统创建进程并分配私有的进程空间;
    (2)加载器把可执行文件的数据段和代码段映射到进程虚拟内存中;
    (3)预取有限的代码段进入实际内存,把CPU的IP指向程序入口点,即可开始执行


    依赖DLL的程序:

    (1)同上,创建进程、映射虚拟内存;
    (2)加载器读取可执行文件的导入符号表,由此找到依赖的DLL
    (3)加载器对依赖的每个DLL调用LoadLibrary,LoadLibrary中处理的事情如下:
    a,加载器为该DLL确定一个合适的基地址(地址重定位)
    b,读取导入和导出符号表,比较应用程序的导入符号与DLL的导出符号是否匹配
    c,通过DLL导入符号表确定该DLL所依赖的其他DLL,同样加载起来
    d,调用DLL的初始化函数
    (4)初始化应用程序的全局变量
    (5)进入应用程序入口点函数开始执行


    四、影响启动性能的因素:
    (1) 程序冷启动的性能大部分取决于IO操作消耗的时间;
    (2) DLL导出过多符号,会引起加载器耗费过多的CPU事件和IO来处理这个符号表;
    (3) 磁盘碎片问题:理想状态下,顺序读取一个文件,不需要磁头寻道操作。但操作系统的文件系统,以块为单位管理物理磁盘空间,当磁盘经过不断的增删改操作后,可能不再具有连续的存储空间。导致一个逻辑上连续的文件,在磁盘上由很多不连续的碎片组成,导致执行IO时需要过多的寻道时间。

    五、优化启动过程的方法:
    (1) 减少动态库数量;
    (2) 减小动态库的尺寸:可以通过编译优化选项;清除冗余代码;
    (3) 优化可执行文件和库文件的代码布局:把库文件中的函数排的更紧密,从而达到减少IO的目的;
            步骤:获得函数调用的顺序文件(.PRF);把这些PRF传给链接器,链接器会自动按照PRF文件把文件在动态库中的位置重新排序(可以尝试一下)
    (4)延迟初始化:可以把一些启动初期不需要的初始化工作延迟到启动后,增强启动体验;延迟的时机:可以在程序空闲时进行处理,在消息循环空闲时处理。
    (5) 多线程化启动:具有以下特点,适合多线程化启动
            启动时需要加载大量动态库,引发大量IO操作;同时这些动态库初始化函数需要执行密集型操作,占用CPU时间。这时候可以将IO等待时间和CPU运行时间交错处理,缩短启动时间。

    备注:IO的实现,是CPU发出命令后,由主板DMP完成,完成后触发中断,然后CPU继续处理,所以IO占用的CPU时间很少。

    https://blog.csdn.net/hellokandy/article/details/70676563

  • 相关阅读:
    common.js
    数据库_day05_查询语句及JDBC
    数据库_day04_基本的增删改查操作
    Java 抽象类、普通类、接口的区别
    java中ArrayList和LinkedList的区别
    数据库_day03_对数据库的基本操作
    java_day18_集合框架map和list
    java_day17_socket,tcp协议传输
    java_day16_读写锁,fork-join框架
    java_day15_线程,匿名内部类,线程安全
  • 原文地址:https://www.cnblogs.com/findumars/p/8734216.html
Copyright © 2020-2023  润新知