聊一聊Integer的緩存機制問題

来源:https://www.cnblogs.com/coderacademy/p/18044486
-Advertisement-
Play Games

在Java編程中,Integer類作為基本類型int的包裝器,提供了對象化的操作和自動裝箱與拆箱的功能。從JDK5開始引入了一項特別的優化措施——Integer緩存機制,它對於提升程式性能和減少記憶體消耗具有重要意義。接下來我們由一段代碼去打開Integer緩存機制的秘密。 public static ...


在Java編程中,Integer類作為基本類型int的包裝器,提供了對象化的操作和自動裝箱與拆箱的功能。從JDK5開始引入了一項特別的優化措施——Integer緩存機制,它對於提升程式性能和減少記憶體消耗具有重要意義。接下來我們由一段代碼去打開Integer緩存機制的秘密。

public static void main(String[] args) {  
    Integer i1 = 100;  
    Integer i2 = 100;  
    System.out.println(i1 == i2);  
    Integer i3 = 1000;  
    Integer i4 = 1000;  
    System.out.println(i3 == i4);  
}

至於答案是什麼呢?我們接著往下看,等你看完就明白了。

當你在你的Idea中寫出這段代碼的時候,Idea就會提示你要使用equals()方法區比較大小,因為Integer是對象,對象的值比較要用equals()方法,而不是使用==,這裡我們主要是研究一下Integer的緩存機制。

Integer緩存是什麼

Java的Integer類內部實現了一個靜態緩存池,用於存儲特定範圍內的整數值對應的Integer對象。預設情況下,這個範圍是-128至127。當通過Integer.valueOf(int)方法創建一個在這個範圍內的整數對象時,並不會每次都生成新的對象實例,而是復用緩存中的現有對象。我們看一下Integer.valueOf(int)的源碼:

@HotSpotIntrinsicCandidate  
public static Integer valueOf(int i) {  
    if (i >= IntegerCache.low && i <= IntegerCache.high)  
        return IntegerCache.cache[i + (-IntegerCache.low)];  
    return new Integer(i);  
}

對於Integer.valueOf(int)方法來說,由於這個方法經常用於將基本類型int轉換為包裝器對象,所以它使用了@HotSpotIntrinsicCandidate註解,這樣HotSpot JVM可能會提供一種更為高效的內部實現來處理自動裝箱操作。而IntegerCacheInteger內部的一個靜態類,負責緩存整數對象。它在類載入時被初始化,創建並緩存範圍內的所有整數對象。我們看一下IntegerCache的源碼:

private static class IntegerCache {  
    // 緩存範圍的下限,預設為-128  
    static final int low = -128;  
    // 緩存範圍的上限,初始化時動態計算(基於系統屬性或預設值127)  
    static final int high;  
    // 存儲在緩存範圍內所有Integer對象的數組  
    static final Integer cache[];  
    // 靜態初始化塊,在類載入時執行  
    static {  
        // 初始設定high為127  
        int h = 127;  
        // 嘗試從系統屬性獲取用戶自定義的最大整數值  
        String integerCacheHighPropValue =  
                VM.getSavedProperty("java.lang.Integer.IntegerCache.high");  
        // 如果系統屬性存在並且可以轉換為int類型,則更新high值  
        if (integerCacheHighPropValue != null) {  
            try {  
                int i = parseInt(integerCacheHighPropValue);  
                // 確保high至少為127,並且不超過Integer.MAX_VALUE允許的最大數組大小  
                h = Math.max(i, 127);  
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);  
            } catch( NumberFormatException nfe) {  
            }  
        }  
  
        // 設置最終確定的high值  
        high = h;  
        // 初始化cache數組,長度等於緩存範圍內的整數數量  
        cache = new Integer[(high - low) + 1];  
        // 使用迴圈填充cache數組,創建並存儲對應的Integer對象  
        int j = low;  
        for(int k = 0; k < cache.length; k++) {  
            cache[k] = new Integer(j++);  
        }  
        // 檢查,確保緩存範圍至少包含[-128, 127]  
        // 這是Java語言規範對小整數自動裝箱共用的要求  
        assert IntegerCache.high >= 127;  
    }  
    // 私有構造器,防止外部實例化此內部類的對象  
    private IntegerCache() {}  
}

IntegerCache類在Java虛擬機啟動時創建了一個固定大小的數組,用於緩存指定範圍內所有的Integer對象。這樣在後續程式運行過程中,對於這些範圍內的整數進行裝箱操作時,可以直接從緩存中獲取已存在的對象,以提升性能並減少記憶體開銷。同時,它也提供了根據系統屬性(-Djava.lang.Integer.IntegerCache.high)來自定義緩存上限的能力,並確保滿足Java語言規範關於小整數自動裝箱共用的規定。

Integer.value(int)方法中,如果int的值在IntegerCache返回的lowhigh之內,則直接返回IntegerCache中緩存的對象,否則重新new一個新的Integer對象。

而文章開頭示例中,我們使用Interge i1 = 100的方式其實是Java的自動裝箱機制,整數字面量100是一個基本類型的int值。當賦值給一個Integer引用變數i時,編譯器會隱式地調用Integer.valueOf(int)方法將這個基本類型的int值轉換為Integer對象。

整數在編程中經常被使用,特別是在迴圈計數等場景中,通過緩存整數對象,可以大幅度減少相同整數值的對象創建,從而減小記憶體占用。

由此我們可以看出因為100在[-128, 127]之內,所以i1 == i2列印true,而1000不在[-128, 127]之內,所以i3 == i4列印false
image.png

我們嘗試使用java.lang.Integer.IntegerCache.high調整一下high為1000,然後看一下效果:
image.png
image.png
列印結果都是true。

當然這個上限不要隨意去調整,調整之前,需要仔細評估應用程式的實際需求和性能影響。儘量選擇在[-128, 127]範圍內的整數值,以充分利用Integer緩存機制。

註意事項

  • 比較: 由於緩存的存在,在-128至127之間的Integer對象在進行==運算符比較時,結果可能是true,因為它們指向的是同一個記憶體地址。而在緩存範圍之外創建的Integer對象即使值相等,也會視為不同的對象,因此使用==比較會返回false。不論是否啟用緩存,對於任何兩個Integer對象,只要其包含的整數值相同,調用equals()方法始終會返回true。所以我們在比較對象時一定要使用equals()方法。

  • 不適用於所有場景: 當使用new Integer(i)直接創建Integer對象時,不會利用緩存。

  • 不要隨意去擴展緩存的上下限

總結

Integer緩存機制是Java中的一項性能優化措施,通過緩存一定範圍內的整數對象,既能減小記憶體開銷,又能提高性能。

本文已收錄於我的個人博客:碼農Academy的博客,專註分享Java技術乾貨,包括Java基礎、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中間件、架構設計、面試題、程式員攻略等


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Maven安裝本地的jar包 如果沒配置Maven的環境變數,需要先CD到maven的安裝目錄,因為沒配置環境變數,mvn命令是無法在maven安裝目錄以外的目錄運行。 cd C:\Maven\apache-maven-3.6.3\bin 然後執行下麵命令格式如下: mvn install:inst ...
  • CMS GC的英文名為:“Mostly Concurrent Mark and Sweep Garbage Collector” (最大-併發-標記-清除-垃圾收集器)。 作用範圍: 老年代 演算法: 併發標記清除演算法。 啟用參數:-XX:+UseConMarkSweepGC預設回收線程數:(處理器核 ...
  • 依賴管理有gradle和maven,在這裡選擇比較常用和方便的Maven作為工程項目和依賴管理工具來搭建SpringCloud實戰工程。主要用到的maven管理方式是多模塊和bom依賴管理。 ...
  • pandas中的cut函數可將一維數據按照給定的區間進行分組,併為每個值分配對應的標簽。其主要功能是將連續的數值數據轉化為離散的分組數據,方便進行分析和統計。 1. 數據準備 下麵的示例中使用的數據採集自王者榮耀比賽的統計數據。數據下載地址:https://databook.top/。 導入數據: ...
  • 題目描述 如果一個國家滿足下述兩個條件之一,則認為該國是 大國 : 面積至少為 300 萬平方公裡 人口至少為 2500 萬 編寫解決方案找出大國的國家名稱、人口和麵積 按任意順序返回結果表,如下例所示 測試用例 輸入: name continent area population gdp Afgh ...
  • Qt 是一個跨平臺C++圖形界面開發庫,利用Qt可以快速開發跨平臺窗體應用程式,在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實現圖形化開發極大的方便了開發效率,本章將重點介紹如何運用`QThread`組件實現多線程功能。 ...
  • 前言 在電商、外賣、預約服務等場景中,訂單超時自動取消是一個常見的業務需求。這一功能不僅提高了系統的自動化程度,還為用戶提供了更好的體驗。需求如下: TODO 如果用戶在生成訂單後一定時間未支付,則系統自動取消訂單。 接下來就用 SpringBoot 實現訂單超時未支付自動取消的幾種方案,並提供相應 ...
  • 在如今的商業環境中,企業信息的準確性和可信度是非常重要的。尤其是在與其他公司進行合作或者與銀行等金融機構進行業務往來時,對企業的背景和信用度有著更高的要求。那麼如何有效地驗證企業的信息是否真實可信呢?挖數據平臺的獲取企業裁判文書介面 - GetJudicialDocuments將成為你的得力助手。 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...