成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

性能優化之動態加載

原創 精選
開發 前端
動態加載技術的核心思想是在程序運行時才加載所需的模塊或組件,而不是在編譯時靜態鏈接。這種技術帶來了許多優勢,如代碼的模塊化、解耦、易于維護和擴展等。

在過去近三十年的職業生涯里,有幾年專注于運行時環境的開發與實現。在runtime中,動態加載技術是其中的基石之一。動態加載技術是指在系統運行過程中,根據需要把程序和數據從外存或網絡加載到內存中的過程。其中,lazy loading(懶加載),也被稱為延遲加載,是動態加載技術的一種常見實現方式。

圖片圖片


1. 什么是動態加載

所謂動態加載,指的是程序在運行期間需要調用某一模塊的功能時,由加載器將該模塊即時載入內存,進行相應的重定位處理后將控制權交還調用程序。動態加載機制運用動態鏈接的原理使得系統具有動態的加載和動態解析的能力,模塊只有在被調用執行時才被鏈接,進入系統執行。

動態加載一般分為下載、加載和卸載三個操作,其中下載完成從遠程下載目標模塊到本地,加載操作來完成讀入模塊到內存,然后對模塊未解析的外部引用進行解析(一般地,也就是符號解析和重定位)使之可以運行的過程。當模塊不再使用時就從內存中卸載。 

1.1 動態加載中的基本概念——模塊

模塊是數據說明、可執行語句等程序對象的集合,它單獨命名而且可以通過名字來訪問,模塊設計者可以通過有選擇地在接口上輸出其特性以達到控制其特性的目的。沒被輸出的特性不能被模塊外部訪問,因此防止了模塊被誤用并且保證了模塊的封裝獨立性。

在模塊化編程思想中,把程序分割成若干個獨立的模塊,然后逐塊編程和獨立編譯,形成獨立的可加載模塊,模塊在被加載前保持本身的獨立性。一個應用可以由多個獨立模塊組成,獨立的模塊構成一個應用有兩種方法:靜態鏈接和動態鏈接。靜態鏈接是獨立模塊事先鏈接好,在解決了所有的外部引用之后,編譯生成一個可執行文件,隨后裝入內存就可以執行。進程在執行的過程中,代碼段和數據段的位置都不能改變。

可加載模塊作為編譯單元被獨立編譯,這就意味著編譯器會核實一個引入模塊的每個引用同其根模塊的一致性。模塊鏈是所有被加載的目標模塊依據模塊之間的依賴關系被動態添加的一個鏈表,查詢時只需要對該鏈表進行查找。在動態加載中,模塊直到被載入前都保持獨立。

一個模塊可能與系統中的其他模塊無關,也有可能與其中的一些模塊進行交互,模塊之間的交互就是模塊間的通信。

1.2 動態加載的技術基礎——動態鏈接

動態鏈接是系統在運行過程中根據需要把外部獨立模塊的可執行代碼鏈接到系統中使之成為運行系統的一部分的過程。動態鏈接在執行過程中,允許在它的地址空間中增加、清除、取代或重定位目標模塊。換句話說,允許程序發生變化。在程序執行的生命周期內,程序可以加入新的模塊、清除舊的模塊、甚至可以演變成一個完全不同的程序。

動態鏈接的一個典型應用就是動態鏈接庫。動態鏈接庫是一個可以被其它應用程序共享的程序模塊,其中封裝了一些可以被共享的例程和資源。 

動態鏈接庫是從C語言函數庫和Pascal庫單元的概念發展而來的。動態鏈接庫不用重復編譯或鏈接,一旦裝入內存, 庫中的函數可以被系統中任何正在運行的應用程序所使用,而不必再將動態鏈接庫的另一拷貝裝入內存。動態鏈接所調用的函數代碼并沒有被拷貝到應用程序的可執行文件中去,而是僅僅在其中加入了所調用函數的描述信息(往往是一些重定位信息)。只有當應用程序被裝入內存開始運行時,在操作系統的管理下,才在應用程序與相應的動態鏈接庫之間建立鏈接關系。

采用這種方法,動態鏈接庫達到了復用代碼的極限。另一個方便之處是對動態鏈接庫中函數的修改可以自動傳播到所有調用它的程序中,而不必對程序作任何改動或處理。

以windows 為例,動態鏈接庫的實現方法主要有兩種:

① 加載時動態鏈接(Load-time Dynamic Linking) 

這種用法的前提是在編譯之前已經明確知道要調用DLL中的哪幾個函數,編譯時在目標文件中只保留必要的鏈接信息,而不含DLL函數的代碼;當程序執行時,利用鏈接信息加載DLL函數代碼并在內存中將其鏈接入調用程序的執行空間中,其主要目的是便于代碼共享。 

②運行時動態鏈接(Run-time Dynamic Linking) 

這種方式是指在編譯之前并不知道將會調用哪些DLL函數,完全是在運行過程中根據需要決定應調用哪個函數,并用LoadLibrary和GetProcAddress動態獲得DLL函數的入口地址。 

在C/C++中,動態加載的功能可以很容易地利用動態鏈接庫來實現。Win32 API函數LoadLibrary和FreeLibrary提供了在運行時刻加載新的功能模塊和釋放內存空間的功能。需要被更新的功能模塊被封裝在動態連接庫中,主程序利用LoadLibrary函數裝載該動態鏈接庫,然后調用其中的功能模塊。需要更新某功能模塊的時候,首先終止運行該功能模塊,利用FreeLibrary函數卸載現有的動態鏈接庫,通過網絡或者是其他通訊端口將新的動態鏈接庫文件發送到指定目錄下,然后通過再次調用LoadLibrary函數裝載新的動態鏈接庫就可以完成動態加載新模塊的功能。

2. 動態加載的一般原理

動態加載機制所涉及到的關鍵問題包括加載模塊的格式、模塊間通信機制、符號管理等等。

可動態加載的模塊有很多種格式類型。比如DOS下的.COM文件和.EXE文件,UNIX 的下a.out文件、ELF文件,以及.OBJ文件等都可以作為可加載模塊被鏈接入系統。對于可重定位的模塊還要包括處理目標代碼時所需的擴展符號和重定位信息,比如符號表、重定位信息和字符串表等。模塊間的通信方法可以參照進程間的通信方法,不同進程之間的通信有很多種方法:消息隊列、管道和共享內存等。符號管理是設計與實現動態加載機制的前提,也是符號解析和重定位技術的基礎。目標模塊按照不同的類型讀入內存后,不能馬上就融入系統運行,動態加載機制還需要對其進行處理,也就是解決模塊中符號的外部引用(符號解析)和重定位,這是動態加載過程中最重要的一個步驟。

動態加載是通過把符號的外部參考插入到運行時鏈接的目標文件中而實現,具有兩個特點: 

①動態的加載,就是當這個運行的模塊在需要的時候才被映射入運行模塊的虛擬內存空間中。如果一個模塊在運行中要調用到另一模塊中的函數,而在沒有調用這個模塊中的其它函數之前,不會把該模塊加載到系統中(也就是內存映射)。 

②動態的解析,就是存在于另一模塊中的函數被調用的時候,才會去把這個函數在虛擬內存空間的起始地址解析出來,再寫到調用模塊中特定的存儲地址內。例如,一個模塊調用了另一個模塊中的函數,那么該函數的地址直到被調用的時候才會被解析出來。 

3. 動態加載的價值

動態加載技術對提高系統性能,提升可擴展性,保證系統的可靠性,延長系統生命周期,降低系統開發成本都具有十分重要的意義。

對于程序中不可忽視的錯誤,或者不能完全滿足用戶的需求,或者使用過程中需要不斷地修改和升級等等,其對應的修改和升級都會往往導致停機維護。而停機對于如金融處理系統、電信交換機系統、交通控制系統,以及一些關鍵的軍事應用上的衛星系統等等,用戶不能忍受系統中斷服務。因此,系統的在線擴展目前已經成為系統軟件的一個基本需求,在系統運行狀態下可以通過動態的添加模塊來配置系統,也就是動態加載機制。動態加載也使系統的升級變得更為方便。升級時開發人員不必重新寫整個系統,即可將升級限制在系統的一個或更多部分,例如如某種算法或某個數據表格。

動態模塊升級還僅取決于基礎系統提供的功能API(應用編程接口),而非取決于基礎系統的靜態地址。這意味著,一個動態模塊可支持多個產品版本,只要所有版本提供的API相同即可。

另外,動態加載也是系統調試和功能完善的重要手段,具有動態加載功能的系統可以隨時更新系統的程序,十分便于系統的調試、維護和功能的完善。 

4. 操作系統內核的動態加載

Linux 內核模塊是Linux中內存加載的一個特殊部分,它可以在不重啟整個系統的情況下動態加載和卸載,具有很高的靈活性。在內核模塊動態加載時,可以節約相當多的系統資源,而且還能避免不必要的內核模塊以及它們的依賴組件被不必要地加載到內存中,從而提高系統的性能。

為了實現動態加載內核模塊,Linux提供了系統調用(System call)機制。它是一種專門用于在操作系統中執行某一操作的特殊函數。當用戶或應用程序要求加載內核模塊時,系統會調用合適的系統調用。例如,可以使用“insmod”系統調用動態加載內核模塊,在不需要的時候用rmmod命令卸載模塊。

Linux內核動態加載機制的一般工作流程如下:

  • 編寫內核模塊代碼:開發者編寫內核模塊代碼,實現特定的功能。這些代碼通常以C語言編寫,并使用Linux內核提供的API進行編程。
  • 編譯內核模塊:開發者使用特定的編譯工具鏈,將內核模塊代碼編譯成可加載的模塊文件(通常是.ko文件)。
  • 加載內核模塊:在系統運行期間,用戶可以通過執行insmod命令,將編譯好的內核模塊加載到內核中。加載過程包括將模塊代碼映射到內核地址空間、初始化模塊等步驟。
  • 使用內核模塊:一旦內核模塊被加載,它的功能就可以被內核和其他系統組件使用。例如,如果加載的是一個驅動程序模塊,那么內核就可以通過該模塊與相應的硬件設備通信。
  • 卸載內核模塊:當不再需要某個內核模塊時,用戶可以執行rmmod命令將其從內核中卸載。卸載過程包括清理模塊資源、撤銷模塊映射等步驟。

盡管有一些約束,使用eBPF 也可以實現內容模塊中的細粒度動態加載。

5. Android 中的動態加載框架

Java反射通常用于檢測和改變應用程序運行在虛擬機中的表現。使用方法Class.forName獲得該類的Class文件,對得到的類用getField方法獲得類的成員變量,用getMethod方法獲得類的成員方法,也可以通過得到的成員方法的invoke方法執行該成員方法。對于得到的Field類型的成員變量,可以通過它的set方法替換掉該變量。 

為完成Android的動態加載,需要修改系統底層源碼,用到了大量的Java反射方法。讓系統能啟動插件組件,使用反射方法替換掉應用層發送給系統的組件名稱,從而讓系統啟動插件組件。對于不同插件的資源加載問題,同樣是通過反射執行系統資源管理等方法來解決的。

參考DruidPlugin 的實現, 我們可以得到如下的Android 動態加載框架:

圖片圖片

下列簡要介紹每個模塊: 

  • 解析模塊:解析插件安裝包文件,獲得插件的所有信息。 
  • Manifest管理模塊:解析結果,管理多個插件的manifest文件的替換和更新。 
  • 資源加載模塊:管理宿主與多個插件程序編譯后生成的資源id索引表,以便正常地通過資源id加載資源。 
  • 代理插件模塊:實現插件與宿主間的替換工作,讓系統以能夠啟動插件組件。 
  • 生命周期管理模塊:使插件activity組件在宿主程序中能與普通的activity一樣,擁有所有的生命周期方法,能夠正常地運行。
  • 插件管理模塊:用于管理諸如插件的添加、刪除、更新等操作。 
  • 安全模塊:保證框架的安全性,確定通過網絡通信得到的插件文件沒有被修改。 
  • 啟動插件模塊:生成多種插件的啟動器,用于加載與啟動插件。

該框架位于Framework層與應用層之間,作為應用程序與Android系統的中間橋梁,通過修改系統的方法調用,從而實現插件的加載。

其中, 插件啟動器的onCreate方法示例偽代碼如下:

1:thread <-Reflector.getActivityThread(app) //獲取ActivityThread 
2:base <- getInstrumentationByReflect(thread) //獲得反射Instrumentation屬性 
3:wrapper <- InstrumentationReplace(base) //修改 
4:setInstrumentationByReflect(wrapper) //重新注入
5:setMessageHandlerByReflect(callBack) //反射設置ActivityThread的m Callback 

動態加載的過程如下所示:

圖片圖片

其中, activity,bundle,uri 等插件中涉及的組件和參數同樣需要做相應的調整。

6. 前端系統的動態加載

對PHP 開發環境下MVC 模式的網站代碼設計來說,分離的組織代碼路徑的獲取是令人頭疼,也是代碼運行中最容易產生錯誤的地方。為此,創建一個動態路徑的加載應用會極大方便編碼,提升開發效率。

用戶首先訪問入口頁面視圖,視圖請求控制器,控制器響應特定行為,獲取相應模型數據,而后將處理結果反饋到視圖中呈現給用戶。因而,在訪問請求中需明確控制器和控制器執行的行為名稱。為實現控制器類中方法能調用不同視圖和模型,需要在實例化類對象之前,加載類的定義,即要完成對不同存儲位置下類的引用。為優化代碼的性能,節省無謂的精力消耗,應用類自動加載方案。將自動加載類__autoLoad()方法運用pl_auto?load_register()重新注冊改寫,當代碼解析為新引用類時,自動調用改寫方法,計算路由路徑地址予以實例化加載,以實現不同文件目錄下的類的自動加載。示例代碼如下:

private static function autoLoad($class_name){
    $class_map=array('MySqlDB' => CORE_PATH."MySqlDB.class.php",'Base' => CORE_PATH."Base.class.php" );
    if(isset($class_map[$class_name])) require $class_map[$class_name];
    elseif(substr($class_name, -5) == "Model") require MODEL_PATH.$class_name.".class.php";
    elseif(substr($class_name, -10) == "Controller") require __URL__.$class_name.".class.php"; 
}

作為是一種網頁優化技術,動態加載可以在網頁加載時延遲加載不必要的資源,以提高頁面的加載速度和性能。例如,在VUE中引入百度開源的echart包用于數據統計的繪圖。

<template>
  <div>using echart in vue project</div>
  <div id="c1" style="width: 600px; height: 400px"></div>
</template>
<script setup lang="ts">
import * as echarts from "echarts";
import { onMounted } from "vue";

onMounted(() => {
  const dom = document.getElementById("c1");
  var myChart = echarts.init(dom as HTMLElement);

  myChart.setOption({
    title: {
      text: "ECharts Bar usage",
    },
    tooltip: {},
    xAxis: {
      data: ["AA", "BB", "CC", "DD", "EE", "FF"],
    },
    yAxis: {},
    series: [
      {
        name: "產量",
        type: "bar",
        data: [5, 10, 15, 12, 10, 20],
      },
    ],
  });
});
</script>

采用普通的加載方式,可以在路由配置中直接導入該頁面:

import VueComponent from "@/pages/vue.vue";
const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: "/login", component: () => import("@/pages/login.vue") },
    {
      path: "/dashboard",
      component: Dashboard,
      children: [
        { path: "/", component: () => import("@/pages/dashboard/index.vue") },
        { path: "/vue", component: VueComponent },
        { path: "/react", component: () => import("@/pages/react.vue") },
      ],
    },
  ],
});

會發現下載的包很大有1M多,在一般的網絡條件下,至少5秒以上,用戶體驗交差。如果采用動態加載,性能則會有較大的提升。

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: "/login", component: () => import("@/pages/login.vue") },
    {
      path: "/statistic",
      component: Statistic,
      children: [
        { path: "/", component: () => import("@/pages/statistic/index.vue") },
        { path: "/vue", component: () => import("@/pages/vue.vue") },
        { path: "/react", component: () => import("@/pages/react.vue") },
      ],
    },
  ],
});

采用延遲加載之后,加載時間可以回歸到1秒以內,用戶體驗的提升是顯著的。

7. 小結

動態加載技術的核心思想是在程序運行時才加載所需的模塊或組件,而不是在編譯時靜態鏈接。這種技術帶來了許多優勢,如代碼的模塊化、解耦、易于維護和擴展等。

動態加載使得代碼更加模塊化,降低了系統的復雜度,還有助于提高代碼的可重用性,因為相同的模塊可以在多個地方使用。動態加載能夠實現代碼的解耦,有助于提高團隊協作效率,并提高系統的可維護性。掌握動態加載技術需要對編程語言、操作系統、網絡通信等方面有深入的了解。因此,學習和實踐動態加載技術有助于程序員提高自己的系統架構能力和編程技能。

動態加載技術在軟件開發領域具有廣泛的應用場景。合理使用動態加載技術不僅可以提高系統的可維護性和可擴展性,還可以提升程序員的系統架構能力和編程技能。因此,對于現代軟件開發者來說,掌握動態加載技術是非常必要的。

責任編輯:武曉燕 來源: 喔家ArchiSelf
相關推薦

2021-07-29 14:20:34

網絡優化移動互聯網數據存儲

2022-02-16 14:10:51

服務器性能優化Linux

2021-11-29 11:13:45

服務器網絡性能

2009-06-30 11:23:02

性能優化

2018-01-09 16:56:32

數據庫OracleSQL優化

2019-12-13 10:25:08

Android性能優化啟動優化

2013-02-20 14:32:37

Android開發性能

2023-07-19 12:24:48

C++constexpr?語句

2011-07-11 15:26:49

性能優化算法

2022-01-10 08:50:13

URL前端頁面

2013-09-04 14:22:59

JavaScript性能優化

2014-10-09 09:48:14

JavaScript

2011-06-14 14:17:23

性能優化系統層次

2021-07-16 23:01:03

SQL索引性能

2013-09-17 10:32:08

Android性能優化數據庫

2023-04-10 11:18:38

前端性能優化

2011-06-14 11:14:10

性能優化代碼

2017-01-19 19:07:28

iOS進階性能優化

2011-06-14 14:32:46

性能優化

2023-11-01 17:57:56

React應用程序性能
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人精品国产一区二区4080 | 国产乱码一二三区精品 | 午夜专区 | 色综合视频 | 国产成人精品久久二区二区91 | 精品久久久久久国产 | 午夜ww| 亚洲最大福利网 | 国产精品综合色区在线观看 | 日韩亚洲视频 | 天天操伊人 | 黄一级| 日韩国产一区二区三区 | 亚洲精品在线播放 | 亚洲网视频| 欧美精品乱码久久久久久按摩 | 国产黄色在线观看 | 青青草亚洲 | 国产精品免费大片 | 午夜精品久久久久久不卡欧美一级 | 国内精品久久久久久 | 国产精品一区三区 | 精品麻豆剧传媒av国产九九九 | 97视频在线免费 | 久久久123 | 99精品视频在线 | 久久精品国产久精国产 | 国产精品久久久久久婷婷天堂 | 国产亚洲精品a | 综合激情网 | 欧美日韩精品一区 | 欧美在线高清 | 久久久精 | 精品国产鲁一鲁一区二区张丽 | 久久精品国产99国产精品 | 久久久久免费精品国产小说色大师 | 中文在线一区 | 久久成人精品视频 | 国产一区二区三区在线 | 激情综合五月 | 91精品国产91综合久久蜜臀 |