九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
探查內(nèi)存不足(內(nèi)存泄露)問題

Java 堆 - 這是 JVM 用來分配 java 對象的內(nèi)存。java 堆內(nèi)存的最大值用 java 命令行中的 .Xmx 標志來指定。如果未指定最大的堆大小,那么該極限值由 JVM 根據(jù)諸如計算機中的物理內(nèi)存量和該時刻的可用空閑內(nèi)存量這類因素來決定。始終建議您指定最大的 java 堆值。本地內(nèi)存 - 這是 JVM 用于其內(nèi)部操作的內(nèi)存。JVM 將使用的本地內(nèi)存堆數(shù)量取決于生成的代碼量、創(chuàng)建的線程、GC 期間用于保存 java 對象信息的內(nèi)存,以及在代碼生成、優(yōu)化等過程中使用的臨時空間。

如果有一個第三方本地模塊,那么它也可能使用本地內(nèi)存。例如,本地 JDBC 驅(qū)動程序?qū)⒎峙浔镜貎?nèi)存。

最大本地內(nèi)存量受到任何特定操作系統(tǒng)上的虛擬進程大小限制的約束,也受到用 .Xmx 標志指定用于 java 堆的內(nèi)存量的限制。例如,如果應用程序能分配總計為 3 GB 的內(nèi)存量,并且最大 java 堆的大小為 1 GB,那么本地內(nèi)存量的最大值可能在 2 GB 左右。

進程大小 - 進程大小將是 java 堆、本地內(nèi)存與加載的可執(zhí)行文件和庫所占用內(nèi)存的總和。在 32 位操作系統(tǒng)上,進程的虛擬地址空間最大可達到 4 GB。從這 4 GB 內(nèi)存中,操作系統(tǒng)內(nèi)核為自己保留一部分內(nèi)存(通常為 1 - 2 GB)。剩余內(nèi)存可用于應用程序。

Windows缺省情況下,2 GB 可用于應用程序,剩余 2 GB 保留供內(nèi)核使用。但是,在 Windows 的一些變化版本中,有一個 /3GB 開關可用于改變該分配比率,使應用程序能夠獲得 3 GB。有關 /3GB 開關的詳細信息,可以在以下網(wǎng)址中找到:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ddtools/hh/ddtools/bootini_1fcj.asp

RH Linux AS 2.1 - 3 GB 可用于應用程序。

對于其它操作系統(tǒng),請參考操作系統(tǒng)文檔了解有關配置。

 

進程地址空間和物理內(nèi)存之間的差異

每個進程都獲得其自有的地址空間。在 32 位操作系統(tǒng)中,此地址空間范圍為 0 到 4 GB。此范圍與計算機的可用隨機存取內(nèi)存 (RAM) 或交換空間無關。計算機中的可用物理內(nèi)存總量是該計算機上的可用 RAM 和交換空間之和。所有運行的進程共享這些物理內(nèi)存。

進程內(nèi)的存儲地址是虛擬地址。內(nèi)核將此虛擬地址映射到物理地址上。物理地址指向物理內(nèi)存中的某個位置。在任一給定時間,計算機中運行進程所使用的全部虛擬內(nèi)存的總和不能超過該計算機上可用物理內(nèi)存的總量。

 

為什么會發(fā)生 OOM 問題,JVM 在這種情況下如何處理?

java 堆中的內(nèi)存不足
如果 JVM 不能在 java 堆中獲得更多內(nèi)存來分配更多 java 對象,將會拋出 java 內(nèi)存不足 (java OOM) 錯誤。如果 java 堆充滿了活動對象,并且 JVM 無法再擴展 java 堆,那么它將不能分配更多 java 對象。

在這種情況下,JVM 讓應用程序決定在拋出 java.lang.OutOfMemoryError 后該執(zhí)行什么操作。例如,應用程序可以處理此錯誤,并決定以安全方式自行關閉或決定忽略此錯誤。如果應用程序不處理此錯誤,那么拋出此錯誤的線程將退出(如果您進行 java Thread Dump,那么將看不到該線程)。

在使用 Weblogic Server 的情況下,如果此錯誤是由某個執(zhí)行線程拋出的,則會處理此錯誤并將其記錄在日志中。如果連續(xù)拋出此錯誤,那么核心運行狀況監(jiān)視器線程將關閉 Weblogic Server。

本地堆中的內(nèi)存不足
如果 JVM 無法獲得更多本地內(nèi)存,它將拋出本地內(nèi)存不足(本地 OOM)錯誤。當進程到達操作系統(tǒng)的進程大小限值,或者當計算機用完 RAM 和交換空間時,通常會發(fā)生這種情況。

當發(fā)生這種情況時,JVM 處理本地 OOM 狀態(tài),記錄說明它已用完本地內(nèi)存或無法獲得內(nèi)存的消息,然后退出。如果 JVM 或加載的任何其它模塊(如 libc 或第三方模塊)不處理這個本地 OOM 狀態(tài),那么操作系統(tǒng)將給 JVM 發(fā)送命令 JVM 退出的 sigabort 信號。通常情況下,JVM 收到 sigabort 信號時將會生成一個核心文件。

 

排除故障的步驟確定是 Java OOM 還是本地 OOM

  • 如果 stdout/stderr 消息說明這是一個 java.lang.OutOfMemoryError,那么這就是 Java OOM
  • 如果 stdout/stderr 消息說明無法獲得內(nèi)存,那么這就是本地 OOM

請注意,上述消息僅發(fā)送到 stdout 或 stderr 中,而不發(fā)送到應用程序特定的日志文件(如 weblogic.log)



對于 Java OOM:

  1. 收集和分析 verbose gc 輸出
    1. 在 java 命令行中添加“-verbosegc”標志。這樣將會把 GC 活動信息打印到 stdout/stderr。將 stdout/stderr 重定向到一個文件。運行應用程序,直到該問題重現(xiàn)。
      • 確保 JVM 在拋出 java OOM 之前完成下列任務

        完整 GC 運行:
        執(zhí)行一次完整 GC 運行,并且刪除了所有不可及對象以及虛可及、弱可及、軟可及對象,并回收了那些空間。有關不同級別的對象可及性的詳細信息,可以在以下網(wǎng)址中可找到:
        http://java.sun.com/developer/technicalArticles/ALT/RefObj

        您可以檢查是否在發(fā)出 OOM 消息之前執(zhí)行了完整 GC 運行。當完成一次完整 GC 運行時,將會打印類似如下消息(格式取決于 JVM - 請查看 JVM 幫助信息以了解有關格式)

        [memory ] 7.160: GC 131072K->130052K (131072K) in 1057.359 ms

        以上輸出的格式如下(備注:在此模式下將全部使用相同的格式):

        [memory ] <start>: GC <before>K-><after>K (<heap>K), <total> ms
        [memory ] <start> - start time of collection (seconds since jvm start)
        [memory ] <before> - memory used by objects before collection (KB)
        [memory ] <after> - memory used by objects after collection (KB)
        [memory ] <heap> - size of heap after collection (KB)
        [memory ] <total> - total time of collection (milliseconds)

        但是,沒有辦法斷定是否使用 verbose 消息刪除了軟/弱/虛可及的對象。如果您懷疑在拋出 OOM 時這些對象仍然存在,請與 JVM 供應商聯(lián)系。

        如果垃圾回收算法是一種按代回收算法(對于 Jrockit 為 gencopy 或 gencon,對于其它 JDK 則是缺省算法),您也將看到類似如下的 verbose 輸出:
        [memory ] 2.414: Nursery GC 31000K->20760K (75776K), 0.469 ms

        以上是 nursery GC(即 young GC)周期,它將把活動對象從 nursery(或 young 空間)提升到 old 空間。這個周期對我們的分析不重要。有關按代回收算法的詳細信息,可以在 JVM 文檔中找到。

        如果在 java OOM 之前未發(fā)生 GC 周期,那么這是一個 JVM 錯誤。

        完全壓縮:
        確保 JVM 執(zhí)行了適當?shù)膲嚎s工作,并且內(nèi)存并未成碎片(否則會阻止分配大對象并觸發(fā) java OOM 錯誤)。

        Java 對象要求內(nèi)存是連續(xù)的。如果可用空閑內(nèi)存是一些碎片,那么 JVM 將無法分配大對象,因為它可能無法放入任何可用空閑內(nèi)存塊中。在這種情況下,JVM 將執(zhí)行一次完全壓縮,以便形成更多連續(xù)的空閑內(nèi)存來容納大對象。

    壓縮工作包括在 java 堆內(nèi)存中將對象從一個位置移動到另一個位置,以及更新對這些對象的引用以指向新位置。除非確有必要,否則 JVM 不會壓縮所有對象。這是為了減少 GC 周期的暫停時間。

    我們可以通過分析 verbose gc 消息來檢查 java OOM 是否由碎片引起。如果您看到類似如下的輸出(在此無論是否有可用的空閑 java 堆都會拋出 OOM),那么這就是由碎片引起的。

    [memory ] 8.162: GC 73043K->72989K (131072K) in 12.938 ms
    [memory ] 8.172: GC 72989K->72905K (131072K) in 12.000 ms
    [memory ] 8.182: GC 72905K->72580K (131072K) in 13.509 ms
    java.lang.OutOfMemoryError

    在上述情況中您可以看到,所指定的最大堆內(nèi)存是 128MB,并且當實際內(nèi)存使用量僅為 72580K 時,JVM 拋出 OOM。堆使用量僅為 55%。因此在這種情況下,碎片影響是:即使還有 45% 的空閑堆,內(nèi)存也會拋出 OOM。這是一個 JVM 錯誤或缺陷。您應當與 JVM 供應商聯(lián)系。

  2. 如果 JVM 一切都正常(上一步中提到的所有操作),那么此 java OOM 可能是應用程序的問題。應用程序可能在不斷泄漏一些 java 內(nèi)存,而這可能導致出現(xiàn)上述問題?;蛘?,應用程序使用更多的活動對象,因此它需要更多 java 堆內(nèi)存。在應用程序中可以檢查以下方面:
  1.  
    • 應用程序中的緩存功能 - 如果應用程序在內(nèi)存中緩存 java 對象,則應確保此緩存并沒有不斷增大。對緩存中的對象數(shù)應有一個限值。我們可以嘗試減少此限值,來觀察其是否降低 java 堆使用量。
    • 長期活動對象 - 如果應用程序中有長期活動對象,則可以嘗試盡可能減少這些對象的存在期。例如,調(diào)整 HTTP 會話超時值將有助于更快地回收空閑會話對象。
    • 內(nèi)存泄漏 - 內(nèi)存泄漏的一個例子是在應用服務器中使用數(shù)據(jù)庫連接池。當使用連接池時,必須在 finally 塊中顯式關閉 JDBC 語句和結(jié)果集對象。這是因為,當從池中調(diào)用連接對象上的 close() 時,只是簡單地把連接返回池中以供重用,并沒有實際關閉連接和關聯(lián)的語句/結(jié)果集對象。
    • 增加 java 堆 - 如果可能的話,我們也可嘗試增加 java 堆,以觀察是否能解決問題。

    Java 軟引用也可用于數(shù)據(jù)緩存,當 JVM 用完 java 堆時,可以保證刪除軟可及對象。


  2. 如果上述建議都不適用于該應用程序,那么,我們需要使用一個基于 JVMPI(JVM 事件探查器接口)的事件探查器(如 Jprobe 或 OptimizeIt)來找出哪些對象正在占用 java 堆。事件探查器還提供 java 代碼中正在創(chuàng)建這些對象的位置的詳細信息。本文檔并不介紹每個事件探查器的詳細信息。可以參考事件探查器文檔來了解如何用事件探查器設置和啟動應用程序。一般而言,基于 JVMPI 的事件探查器需要較高的系統(tǒng)開銷,并會大大降低應用程序的性能。因此,在生產(chǎn)環(huán)境中使用這些事件探查器并不可取。

對于本地 OOM 問題:

  1. 收集下列信息:
    1. .verbosegc 輸出,通過它可監(jiān)視 java 堆使用量。這樣將有助于了解此應用程序的 java 內(nèi)存要求。
    應當注意,指定的最大堆內(nèi)存量(在 java 命令行中使用 Xmx 標志)與應用程序的實際 java 堆使用量無關,其在 JVM 啟動時被保留,并且此保留內(nèi)存不能用于其它任何用途。

    在使用 Jrockit 時,使用 -verbose 來代替 -verbosegc,因為這可以提供 codegen 信息以及 GC 信息。
    1. 定期記錄進程虛擬內(nèi)存大小,從啟動應用程序時起直到 JVM 用完本地內(nèi)存。這樣將有助于了解此進程是否確實達到該操作系統(tǒng)的大小限值。
    在 Windows 環(huán)境下,使用下列步驟來監(jiān)視虛擬進程大?。?/font>
    1.  
      1. 在“開始” -> “運行”對話框中,輸入“perfmon”并單擊“確定”。
      2. 在彈出的“性能”窗口中,單擊“+”按鈕(圖表上部)。
      3. 在顯示的對話框中選擇下列選項:
        • 性能對象:進程(不是缺省的處理器)
        • 從列表中選擇計數(shù)器:虛擬字節(jié)數(shù)
        • 從列表中選擇實例:選擇 JVM (java) 實例
        • 單擊“添加”,然后單擊“關閉”

在 Unix 或 Linux 環(huán)境下,對于一個給定 PID,可以使用以下命令來查找虛擬內(nèi)存大小 - ps -p <PID> -o vsz。

在 Linux 環(huán)境下,單個 JVM 實例內(nèi)的每個 java 線程都顯示為一個獨立的進程。如果我們獲得根 java 進程的 PID,那么這就足夠了??梢允褂?ps 命令的 .forest 選項來找到根 java 進程。例如,ps lU <user> --forest 將提供一個由指定用戶啟動的所有進程的 ASCII 樹圖。您可以從該樹圖中找到根 java。

  1. 計算機中的內(nèi)存可用性
    如果計算機沒有足夠的 RAM 和交換空間,則操作系統(tǒng)將不能為此進程提供更多內(nèi)存,這樣也會導致內(nèi)存不足。請確保 RAM 與磁盤中的交換空間之和足以滿足該計算機中正在運行的所有進程的需要。
  1. 調(diào)整 java 堆
    如果 java 堆使用量完全在最大堆范圍內(nèi),則減小 java 最大堆將為 JVM 提供更多的本地內(nèi)存。這不是一個解決辦法,而是一個可嘗試的變通方法。由于操作系統(tǒng)限制進程大小,我們需要在 java 堆和本地堆之間尋求一個平衡。

  1. JVM 的本地內(nèi)存使用量
    在加載了所有類并調(diào)用了方法(代碼生成結(jié)束)后,JVM 的本地內(nèi)存用量預計將會幾乎達到穩(wěn)定。對于大多數(shù)應用程序而言,這通常發(fā)生在最初幾小時內(nèi)。此后,JVM 可能會因加載運行時類型、生成優(yōu)化代碼等處理而僅使用少量本地內(nèi)存。

     

    為了縮小問題的范圍,可嘗試禁用運行時優(yōu)化,并檢查這是否會產(chǎn)生任何效果。

    • 在使用 Jrockit 時,可使用 -Xnoopt 標志來禁用運行時優(yōu)化。
    • 在使用 SUN hotspot JVM 時,-Xint 標志將強迫 JVM 在解釋模式中運行(不生成代碼)。

    如果在整個運行過程中,本地內(nèi)存使用量繼續(xù)不斷增加,那么這可能是本地代碼中的內(nèi)存泄漏。

  2. 第三方本地模塊或應用程序中的 JNI 代碼
    檢查您是否在使用類似數(shù)據(jù)庫驅(qū)動程序的任何第三方本地模塊。這些本地模塊也可以分配本地內(nèi)存,泄漏可能從這些模塊中發(fā)生。為了縮小問題的范圍,應嘗試在沒有這些第三方模塊的情況下重現(xiàn)問題。例如,可以使用純 java 驅(qū)動程序來代替本地數(shù)據(jù)庫驅(qū)動程序。

     

    檢查應用程序是否使用一些 JNI 代碼。這也可能造成本地內(nèi)存泄漏,如果可能的話,您可以嘗試在沒有 JNI 代碼的情況下運行應用程序。

  3. 如果在執(zhí)行上述步驟后還不能找到本地內(nèi)存泄漏的根源,那么您需要與 JVM 供應商合作來獲得一個特殊的編譯版本,它可以跟蹤本地內(nèi)存分配調(diào)用,并可提供有關泄漏的更多信息。
本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務
熱點新聞
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服