国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

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

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

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

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

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

Windows缺省情況下,2 GB 可用于應(yīng)用程序,剩余 2 GB 保留供內(nèi)核使用。但是,在 Windows 的一些變化版本中,有一個(gè) /3GB 開關(guān)可用于改變該分配比率,使應(yīng)用程序能夠獲得 3 GB。有關(guān) /3GB 開關(guān)的詳細(xì)信息,可以在以下網(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 可用于應(yīng)用程序。

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

 

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

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

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

 

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

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

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

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

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

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

 

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

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

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



對于 Java OOM:

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

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

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

        [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 時(shí)這些對象仍然存在,請與 JVM 供應(yīng)商聯(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 空間。這個(gè)周期對我們的分析不重要。有關(guān)按代回收算法的詳細(xì)信息,可以在 JVM 文檔中找到。

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

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

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

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

    我們可以通過分析 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,并且當(dāng)實(shí)際內(nèi)存使用量僅為 72580K 時(shí),JVM 拋出 OOM。堆使用量僅為 55%。因此在這種情況下,碎片影響是:即使還有 45% 的空閑堆,內(nèi)存也會拋出 OOM。這是一個(gè) JVM 錯(cuò)誤或缺陷。您應(yīng)當(dāng)與 JVM 供應(yīng)商聯(lián)系。

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

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


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

對于本地 OOM 問題:

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

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

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

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

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

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

     

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

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

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

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

     

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

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

聯(lián)系客服