」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 透過靜態分析、映像初始化和堆疊快照提高效能

透過靜態分析、映像初始化和堆疊快照提高效能

發佈於2024-11-08
瀏覽:260

从整体结构到分布式系统世界,应用程序开发已经走过了漫长的道路。云计算和微服务架构的大规模采用极大地改变了服务器应用程序的创建和部署方式。我们现在拥有独立、单独部署的服务,而不是巨大的应用程序服务器
当需要时。

然而,可能影响这种平稳运行的新玩家可能是“冷启动”。当第一个请求在新产生的工作进程上处理时,冷启动就会启动。这种情况需要在处理实际请求之前进行语言运行时初始化和服务配置初始化。与冷启动相关的不可预测性和执行速度较慢可能会违反云服务的服务级别协议。那么,如何应对这种日益增长的担忧呢?

本机映像:优化启动时间和内存占用

为了解决冷启动的低效率问题,我们开发了一种新颖的方法,涉及点分析、构建时的应用程序初始化、堆快照和提前(AOT)编译。此方法在封闭世界假设下运行,要求所有 Java 类在构建时都已预先确定并可访问。在此阶段,全面的点分析确定所有可访问的程序元素(类、方法、字段),以确保仅编译必要的 Java 方法。

应用程序的初始化代码可以在构建过程中执行,而不是在运行时执行。这允许预先分配 Java 对象并构建复杂的数据结构,然后在运行时通过“映像堆”提供这些数据结构。该映像堆集成在可执行文件中,在应用程序启动时提供立即可用性。这
持续迭代执行点分析和快照,直到达到稳定状态(定点),从而优化启动时间和资源消耗。

详细工作流程

我们系统的输入是 Java 字节码,它可能源自 Java、Scala 或 Kotlin 等语言。该过程统一处理应用程序、其库、JDK 和 VM 组件,以生成特定于操作系统和体系结构的本机可执行文件 - 称为“本机映像”。构建过程包括迭代点分析和堆快照,直到达到固定点,从而允许应用程序通过注册的回调主动参与。这些步骤统称为本机映像构建过程 (图 1)

Enhancing Performance with Static Analysis, Image Initialization and Heap Snapshotting

图 1 – 本机映像构建过程(来源:redhat.com)

点分析

我们采用点分析来确定运行时类、方法和字段的可达性。点到分析从所有入口点(例如应用程序的主要方法)开始,迭代遍历所有可传递可达的方法,直到到达固定点(图2)。

Enhancing Performance with Static Analysis, Image Initialization and Heap Snapshotting

图 2 – 分析点

我们的指向分析利用编译器的前端将 Java 字节码解析为编译器的高级中间表示(IR)。随后,IR 被转换为类型流图。在此图中,节点表示对对象类型进行操作的指令,而边表示节点之间的定向使用边,从定义指向使用。每个节点维护一个类型状态,由可以到达该节点的类型列表和空值信息组成。类型状态通过使用边传播;如果节点的类型状态发生变化,则此更改将传播到所有用途。重要的是,类型状态只能扩展;新类型可以添加到类型状态,但现有类型永远不会被删除。该机制确保
分析最终收敛到一个固定点,导致终止。

运行初始化代码

指向分析在到达局部固定点时指导初始化代码的执行。该代码起源于两个不同的来源:类初始值设定项和在构建时通过功能接口批量执行的自定义代码:

  1. 类初始值设定项: 每个 Java 类都可以有一个由 方法指示的类初始值设定项,该方法初始化静态字段。开发人员可以选择在构建时和运行时初始化哪些类。

  2. 显式回调:开发者可以通过我们系统提供的钩子实现自定义代码,在分析阶段之前、期间或之后执行。

这里提供了用于与我们的系统集成的API。

被动API(查询当前分析状态)

boolean isReachable(Class> clazz);

boolean isReachable(Field field);

boolean isReachable(Executable method);

更多信息,请参阅QueryReachabilityAccess

Active API(注册分析状态更改的回调):

void registerReachabilityHandler(Consumer callback, Object... elements);

void registerSubtypeReachabilityHandler(BiConsumer> callback, Class> baseClass);

void registerMethodOverrideReachabilityHandler(BiConsumer callback, Executable baseMethod);

更多信息,请参阅BeforeAnalysisAccess

在此阶段,应用程序可以执行自定义代码,例如对象分配和较大数据结构的初始化。重要的是,初始化代码可以访问当前的分析状态点,从而启用有关类型、方法或字段的可达性的查询。这是使用DuringAnalysisAccess 提供的各种isReachable() 方法来完成的。利用此信息,应用程序可以构建针对应用程序的可到达段优化的数据结构。

堆快照

最后,堆快照通过像静态字段一样跟随根指针构建对象图,以构建所有可访问对象的全面视图。然后该图填充本机图像的
图像堆,确保应用程序的初始状态在启动时有效加载。

为了生成可达对象的传递闭包,该算法遍历对象字段,使用反射读取它们的值。值得注意的是,映像生成器在 Java 环境中运行。在此遍历期间,仅考虑由指向分析标记为“已读”的实例字段。例如,如果一个类有两个实例字段,但其中一个未标记为已读,则通过未标记字段可访问的对象将从图像堆中排除。

当遇到先前未通过指向分析识别其类的字段值时,该类将被注册为字段类型。此注册确保在点分析的后续迭代中,新类型传播到类型流图中的所有字段读取和传递用法。

下面的代码片段概述了堆快照的核心算法:

Declare List worklist := []
Declare Set reachableObjects := []

Function BuildHeapSnapshot(PointsToState pointsToState)
For Each field in pointsToState.getReachableStaticObjectFields()
Call AddObjectToWorkList(field.readValue())
End For

    For Each method in pointsToState.getReachableMethods()
        For Each constant in method.embeddedConstants()
            Call AddObjectToWorkList(constant)
        End For
    End For

    While worklist.isNotEmpty
        Object current := Pop from worklist
        If current Object is an Array
            For Each value in current
                Call AddObjectToWorkList(value)
                Add current.getClass() to pointsToState.getObjectArrayTypes()
            End For
        Else
            For Each field in pointsToState.getReachableInstanceObjectFields(current.getClass())
                Object value := field.read(current)
                Call AddObjectToWorkList(value)
                Add value.getClass() to pointsToState.getFieldValueTypes(field)
            End For
        End If
    End While
    Return reachableObjects
End Function

综上所述,堆快照算法通过系统地遍历可达对象及其字段来高效地构造堆快照。这可确保仅相关对象包含在图像堆中,从而优化本机图像的性能和内存占用。

结论

总而言之,堆快照过程在本机映像的创建中起着至关重要的作用。通过系统地遍历可达对象及其字段,堆快照算法构建了一个对象图,该对象图表示可达对象从根指针(例如静态字段)的传递闭包。然后将该对象图作为图像堆嵌入到本机映像中,充当本机映像启动时的初始堆。

在整个过程中,算法依赖于分析点的状态来确定哪些对象和字段与包含在图像堆中相关。考虑由点分析标记为“已读”的对象和字段,而排除未标记的实体。此外,当遇到以前未见过的类型时,算法会将它们注册以便在点分析的后续迭代中传播。

总体而言,堆快照通过确保映像堆中仅包含必要的对象来优化本机映像的性能和内存使用情况。这种系统方法提高了本机图像执行的效率和可靠性。

版本聲明 本文轉載於:https://dev.to/yanev/enhancing-performance-with-static-analysis-image-initialization-and-heap-snapshotting-263f?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何使用 javac、Ant 或 Maven 遞歸編譯多個 Java 檔案?
    如何使用 javac、Ant 或 Maven 遞歸編譯多個 Java 檔案?
    如何使用javac 遞歸編譯所有Java 檔案為每個套件使用單獨的shell 指令編譯分佈在多個套件中的大量Java 檔案可能會很乏味包裹。相反,請考慮使用以下方法之一來簡化編譯。 方法1:使用@source產生一個文字檔案(例如,sources.txt) txt),其中列出了要編譯的所有Java文...
    程式設計 發佈於2024-11-08
  • 如何存取 PHP $_GET 數組中的多值參數?
    如何存取 PHP $_GET 數組中的多值參數?
    在 PHP $_GET 陣列中存取多值參數PHP 的 $_GET 超全域數組允許存取查詢字串參數。預設情況下,當為相同參數指派多個值時,僅最後一個值會儲存在 $_GET 中。但是,可以以數組形式檢索此類值。 建立多值$_GET 參數要為查詢字串中的參數傳送多個值,只需使用方括號表示法:http://...
    程式設計 發佈於2024-11-08
  • 如何使用 Python 在文件的特定位置插入一行?
    如何使用 Python 在文件的特定位置插入一行?
    在Python中的文件中間插入一行在文件中的指定位置插入一行,同時保持文件的完整性現有內容可以使用Python 的檔案處理功能來實現。 要在文件中的索引 x 處插入一行,請按照下列步驟操作:開啟檔案進行讀取。 使用 readlines() 方法將整個文件讀入行列表。 使用 insert() 方法在指...
    程式設計 發佈於2024-11-08
  • React、Vue 和 Svelte 中的 JavaScript 框架 – 選擇哪一個?
    React、Vue 和 Svelte 中的 JavaScript 框架 – 選擇哪一個?
    JavaScript 框架在过去几年中取得了显着的发展,成为现代 Web 应用程序的支柱。 2024 年,React、Vue 和 Svelte 脱颖而出,成为最受欢迎的框架,每个框架都有其独特的优点和缺点。如果您正在构建新的 Web 应用程序,选择正确的框架对于项目的成功至关重要。 在本文中,我们将...
    程式設計 發佈於2024-11-08
  • ## 當方法具有指標接收器時,我什麼時候應該避免在 Go 中複製實例?
    ## 當方法具有指標接收器時,我什麼時候應該避免在 Go 中複製實例?
    複製實例時指針接收器的重要性操作資料時,請理解按引用或按值傳遞值的細微差別至關重要。在 Go 中,方法可以使用值接收器或指標接收器來定義,理解這種選擇的含義至關重要,尤其是在複製實例時。 值接收器具有值接收器的方法對它們接收到的值的副本進行操作。方法內所做的任何修改都不會影響原始值。這確保了在複製的...
    程式設計 發佈於2024-11-08
  • 如何修改不可變 Python 字串中的單一字元?
    如何修改不可變 Python 字串中的單一字元?
    錯誤:'str'物件不支援專案分配錯誤:'str'物件不支援專案分配Python字串是不可變的,這意味著一旦創建,它們的單一字元就不能被修改修改的。嘗試直接使用項目分配來修改字元(如代碼s2[j] = s1[i] 所示)會導致錯誤「TypeError: 'st...
    程式設計 發佈於2024-11-08
  • 使用 Java Spring Boot 和 JdbcTemplate 設定 JDBC 以連接到 Databricks
    使用 Java Spring Boot 和 JdbcTemplate 設定 JDBC 以連接到 Databricks
    在軟體開發領域,連接到各種資料來源是一項基本技能。 Databricks 是一個基於雲端的資料分析平台,提供了一種處理和分析大量資料的強大方法。在這篇文章中,我們將探討如何使用 Java 和 Spring 的 JdbcTemplate 來配置 JDBC 連線來連接到 Databricks,讓您能夠充...
    程式設計 發佈於2024-11-08
  • Copilotkit:您的程式設計冒險人工智慧僚機
    Copilotkit:您的程式設計冒險人工智慧僚機
    简介:当人工智能遇见代码(火花四溅) 在不断发展的科技世界中,算法起舞,数据流歌唱,镇上出现了一位新玩家:Copilotkit。这就像有一个非常聪明的朋友,他从不睡觉,不会喝掉你所有的咖啡,也不会因为你凌晨 3 点穿着睡衣编码而评判你。欢迎来到编码的未来,人工智能不仅是辅助,而且是...
    程式設計 發佈於2024-11-08
  • 如何修復 Mac 上的 Java 8 安裝問題
    如何修復 Mac 上的 Java 8 安裝問題
    解決Mac 上Java 8 的安裝問題您關於Mac 上Java 8 安裝檔案的意外位置和兼容性挑戰的查詢重點開發商面臨的共同問題。本文旨在提供一個全面的解決方案來解決這些問題。 安裝異常Oracle的Java安裝程式傾向於將Java 8檔案放在/Library/Java/JavaVirtualMac...
    程式設計 發佈於2024-11-08
  • useMemo 與 useCallback
    useMemo 與 useCallback
    介紹 React 提供了廣泛的鉤子來幫助我們有效地建立動態應用程式。在這些鉤子中,useMemo和useCallback是提高元件效能的重要工具。儘管兩者都有相似的目的——防止不必要的重新計算或函數重新創建——但它們適用於不同的場景。 在本文中,我們將探討 useMemo 和 u...
    程式設計 發佈於2024-11-08
  • 為什麼 MDM 很重要:優勢和商業價值
    為什麼 MDM 很重要:優勢和商業價值
    在当今的数字经济中,数据是每个成功企业的基石。随着组织生成的信息呈指数级增长,主数据的有效管理已成为当务之急。主数据管理 (MDM) 是管理组织关键数据资产(例如客户信息、产品详细信息和财务记录)的战略流程,确保所有部门和系统的准确性、一致性和可访问性。但为什么 MDM 很重要?更重要的是,它能带来...
    程式設計 發佈於2024-11-08
  • 使用 MetaTrader 訂單管理和市場資料收集進行自動交易
    使用 MetaTrader 訂單管理和市場資料收集進行自動交易
    Your AsimovMT class provides a comprehensive interface for interacting with MetaTrader5 (MT5) using Python. However, there are several areas in your c...
    程式設計 發佈於2024-11-08
  • 是什麼導致 Google Chrome 的 Console.log() 中陣列和物件的行為不一致?
    是什麼導致 Google Chrome 的 Console.log() 中陣列和物件的行為不一致?
    Google Chrome 的console.log() 表現出數組和對像不一致的行為了解問題在Google Chrome 中調試代碼時,觀察到console.log() 在處理巢狀數組時表現得很奇怪。記錄數組時,在記錄後修改其內部值會導致記錄的輸出反映更新後的值而不是記錄時的值。 Firefox ...
    程式設計 發佈於2024-11-08
  • 在 PHP 中按物件欄位對物件數組進行排序
    在 PHP 中按物件欄位對物件數組進行排序
    在 PHP 中,有多種方法可以依照物件欄位對物件陣列進行排序。以下是一些常見的方法: 將 usort() 函數與自訂比較函數結合使用 實作自訂排序演算法 利用 array_multisort() 函數 將 usort() 函數與自訂比較函數結合使用 以下是在 PHP 中使用 uso...
    程式設計 發佈於2024-11-08
  • 注意 Java 中的型別轉換
    注意 Java 中的型別轉換
    Java是強類型語言,但仍可在不同類型的原始變數之間傳遞值。例如,我可以將 int 的值指派給 double ,沒有任何問題,只要接收該值的類型的儲存容量可以處理它。 請參閱下面每個原始類型的大小: 將值轉移到具有更大儲存容量的類型有一個技術名稱:「擴大轉換」。該術語在葡萄牙語中通常被翻譯為“放大...
    程式設計 發佈於2024-11-08

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3