一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

jdk17下netty導致堆內(nèi)存瘋漲原因排查

OSC開源社區(qū) ? 來源:OSCHINA 社區(qū) ? 2023-09-12 11:22 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

來源| OSCHINA 社區(qū)

作者 | 京東云開發(fā)者社區(qū)-京東零售 劉鵬

背景:

介紹

天網(wǎng)風控靈璣系統(tǒng)是基于內(nèi)存計算實現(xiàn)的高吞吐低延遲在線計算服務,提供滑動或滾動窗口內(nèi)的 count、distinctCout、max、min、avg、sum、std 及區(qū)間分布類的在線統(tǒng)計計算服務??蛻舳撕头斩说讓油ㄟ^ netty 直接進行 tcp 通信,且服務端也是基于 netty 將數(shù)據(jù)備份到對應的 slave 集群。
a6f6f31a-5096-11ee-a25d-92fbcf53809c.png

低延遲的瓶頸

靈璣第 1 個版本經(jīng)過大量優(yōu)化,系統(tǒng)能提供較大的吞吐量。如果對客戶端設置 10ms 超時,服務端 1wqps/core 的流量下,可用率只能保證在 98.9% 左右,高并發(fā)情況下主要是 gc 導致可用率降低。如果基于 cms 垃圾回收器。當一臺 8c16g 的機器在經(jīng)過第二個版本優(yōu)化后吞吐量超過 20wqps 的時候,那么大概每 4 秒會產(chǎn)生一次 gc。如果按照一次 gc 等于 30ms。那么至少分鐘顆粒度在 gc 時間的占比至少在 (15*30/1000/60)=0.0075。也就意味著分鐘級別的 tp992 至少在 30ms。不滿足相關業(yè)務的需求。

jdk17+ZGC

為了解決上述延遲過高的相關問題,JDK 11 開始推出了一種低延遲垃圾回收器 ZGC。ZGC 使用了一些新技術(shù)和優(yōu)化算法,可以將 GC 暫停時間控制在 10 毫秒以內(nèi),而在 JDK 17 的加持下,ZGC 的暫停時間甚至可以控制在亞毫秒級別。實測在平均停頓時間在 10us 左右,主要是基于一個染色指針和讀屏障做到大多數(shù) gc 階段可以做到并發(fā)的,有興趣的同學可以了解下,并且 jdk17 是一個 lts 版本。

問題:

采用 jdk17+zgc 經(jīng)過相關的壓測后,一切都在向著好的方向發(fā)展,但是在一種特殊場景壓測,需要將數(shù)據(jù)從北京數(shù)據(jù)中心同步給宿遷數(shù)據(jù)中心的時候,發(fā)現(xiàn)了一些詭異的事情

服務端容器的內(nèi)存瘋漲,并且停止壓測后,內(nèi)存只是非常緩慢的減少。

相關機器 cpu 一直保存在 20%(已經(jīng)無流量請求)

一直在次數(shù)不多的 gc。大概每 10s 一次

a704a0fa-5096-11ee-a25d-92fbcf53809c.png

排查之旅

內(nèi)存泄漏排查

第一反應是遇到內(nèi)存瘋漲和無法釋放該問題時,首先歸納為內(nèi)存泄漏問題,感覺這題也簡單明了。開始相關內(nèi)存泄漏檢查:先 dump 堆內(nèi)存分析發(fā)現(xiàn)占用堆內(nèi)存的是 netty 相關的對象,恰好前段時間也有個同學也分享了 netty 下的不合理使用 netty byteBuf 導致的內(nèi)存泄漏,進一步增加了對 netty 內(nèi)存泄露的懷疑。于是開啟 netty 內(nèi)存泄漏嚴格檢查模式 (加上 jvm 參數(shù) Dio.netty.leakDetection.level=PARANOID),重新試跑并沒有發(fā)現(xiàn)相關內(nèi)存泄漏日志。好吧~!初步判定不是 netty 內(nèi)存泄漏。 a721f420-5096-11ee-a25d-92fbcf53809c.png

jdk 與 netty 版本 bug 排查

會不會是 netty 與 jdk17 兼容不好導致的 bug? 回滾 jdk8 測試發(fā)現(xiàn)的確不存在這個問題,當時使用的是 jdk17.0.7 版本。正好官方發(fā)布了 jdk17.0.8 版本,并且看到版本介紹上有若干的 Bug Fixes。所以又升級了 jdk 一個小版本,然而發(fā)現(xiàn)問題仍然在。會不會是 netty 的版本過低?正好看見 gitup 上也有類似的 issue# https://github.com/netty/netty/issues/6125WriteBufferWaterMark's 并且在高版本疑似修復了該問題,修改了 netty 幾個版本重新壓測,然而發(fā)現(xiàn)問題仍然在。

直接原因定位與解決

經(jīng)過上述兩次排查,發(fā)現(xiàn)問題比想象中復雜,應該深入分析下為什么,重新梳理了下相關線索:

發(fā)現(xiàn)回滾至 jdk8 的時候,對應宿遷中心的集群接受到的備份數(shù)據(jù)量比北京中心發(fā)送的數(shù)據(jù)量低了很多

為什么沒有流量了還一直有 gc,cpu 高應該是 gc 造成的(當時認為是 zgc 的內(nèi)存的一些特性)

內(nèi)存分析:為什么 netty 的 MpscUnboundedArrayQueue 引用了大量的 AbstractChannelHandlerContext$WriteTask 對象,。MpscUnboundedArrayQueue 是生產(chǎn)消費 writeAndFlush 任務隊列,WriteTask 是相關的 writeAndFlush 的任務對象,正是因為大量的 WriteTask 對象及其引用導致了內(nèi)存占用過高。

只有跨數(shù)據(jù)中心出現(xiàn)該問題,同數(shù)據(jù)中心數(shù)據(jù)壓測不會出現(xiàn)該問題。

分析過后已經(jīng)有了基本的猜想,因為跨數(shù)據(jù)中心下機房延遲更大,單 channel 信道下已經(jīng)沒法滿足同步數(shù)據(jù)能力,導致 netty 的 eventLoop 的消費能不足導致積壓。 解決方案:增加與備份數(shù)據(jù)節(jié)點的 channel 信道連接,采用 connectionPool,每次批量同步數(shù)據(jù)的時候隨機選擇一個存活的 channel 進行數(shù)據(jù)通信。經(jīng)過相關改造后發(fā)現(xiàn)問題得到了解決。

根因定位與解決

根因定位

雖然經(jīng)過上述的改造,表面上看似解決了問題,但是問題的根本原因還是沒有被發(fā)現(xiàn)

1. 如果是 eventLoop 消費能力不足,為什么停止壓測后,相關內(nèi)存只是緩慢減少,按理說應該是瘋狂的內(nèi)存減少。

2. 為什么一直 cpu 在 23% 左右,按照平時的壓測數(shù)據(jù),同步數(shù)據(jù)是一個流轉(zhuǎn)批的操作,最多也就消耗 5% cpu 左右,多出來的 cpu 應該是 gc 造成的,但是數(shù)據(jù)同步應該并不多,不應該造成這么多的 gc 壓力。

3. 為什么 jdk8 下不會存在該問題

推測應該是有個 netty eventLoop 消費耗時阻塞的操作導致消費能力大幅度下降。所以感覺還是 netty 的問題,于是開了 netty 的相關 debug 日志。發(fā)現(xiàn)了一行關鍵日志

[2023-08-23 1116.163] DEBUG [] - io.netty.util.internal.PlatformDependent0 - direct buffer constructor: unavailable: Reflective setAccessible(true) disabled  
  

順著這條日志找到了本次的問題根因,為什么一個直接內(nèi)存的構(gòu)造器不能使用會導致我們系統(tǒng) WriteTask 消費阻塞, 帶著這個目的去查看相關的源碼。

源碼分析

一) netty 默認會用 PooledByteBufAllocator 來分配直接內(nèi)存,采用類似 jmelloc 的內(nèi)存池機制,每次內(nèi)存不足的時候會通過創(chuàng)建 io.netty.buffer.PoolArena.DirectArena#newChunk 去預占申請內(nèi)存。

  
protected PoolChunk newChunk() {  
     // 關鍵代碼  
        ByteBuffer memory = allocateDirect(chunkSize);  
    }  
}

二) allocateDirect () 是申請直接內(nèi)存的邏輯。大致就是如果能采用底層 unsafe 去申請、釋放直接內(nèi)存和反射創(chuàng)建 ByteBuffer 對象,那么就采用 unsafe。否則就直接調(diào)用 java 的 Api ByteBuffer.allocateDirect 來直接分配內(nèi)存并且采用自帶的 Cleaner 來釋放內(nèi)存。這里 PlatformDependent.useDirectBufferNoCleaner 是個關鍵點,其實就是 USE_DIRECT_BUFFER_NO_CLEANER 參數(shù)配置

PlatformDependent.useDirectBufferNoCleaner() ?  
     PlatformDependent.allocateDirectNoCleaner(capacity) :       ByteBuffer.allocateDirect(capacity);

三) USE_DIRECT_BUFFER_NO_CLEANER 參數(shù)邏輯配置在 PlatformDependent 類的 static {} 里面。

關鍵邏輯:maxDirectMemory==0 和!hasUnsafe () 在 jdk17 下沒有特殊配置都是不滿足條件的,關鍵是 PlatformDependent0.hasDirectBufferNoCleanerConstructor 的判斷邏輯

if (maxDirectMemory == 0 || !hasUnsafe() || !PlatformDependent0.hasDirectBufferNoCleanerConstructor()) {  
    USE_DIRECT_BUFFER_NO_CLEANER = false;  
} else {  
    USE_DIRECT_BUFFER_NO_CLEANER = true;  
  

四) PlatformDependent0.hasDirectBufferNoCleanerConstructor () 的判斷是看 PlatformDependent0 的 DIRECT_BUFFER_CONSTRUCTOR 是否 NULL,回到了剛開的 debug 日志,我們是可以看到在默認情況下 DIRECT_BUFFER_CONSTRUCTOR 該構(gòu)造器是 unavailable 的(unavailable 則為 NULL)。以下代碼具體的邏輯判斷及其偽代碼。

1. 開啟條件一:jdk9 及其以上必須要開啟 jvm 參數(shù) -io.netty.tryReflectionSetAccessible 參數(shù) 2. 開啟條件二:能反射獲取到一個 private DirectByteBuffer 構(gòu)造器,該構(gòu)造器是通過內(nèi)存地址和大小來構(gòu)造 DirectByteBuffer.(備注:如果在 jdk9 以上對 java.nio 有模塊權(quán)限限制,需要加上 jvm 啟動參數(shù) --add-opens=java.base/java.nio=ALL-UNNAMED , 否則會報 Unable to make private java.nio.DirectByteBuffer (long,int) accessible: module java.base does not "opens java.nio" to unnamed module) 所以這里我們默認是沒有開啟這兩個 jvm 參數(shù)的,那么 DIRECT_BUFFER_CONSTRUCTOR 為空值,對應第二部 PlatformDependent.useDirectBufferNoCleaner () 為 false。

  
    // 偽代碼,實際與這不一致  
 ByteBuffer direct = ByteBuffer.allocateDirect(1);  
  
    if(SystemPropertyUtil.getBoolean("io.netty.tryReflectionSetAccessible",  
        javaVersion() < 9 || RUNNING_IN_NATIVE_IMAGE)) {  
         DIRECT_BUFFER_CONSTRUCTOR =  
         direct.getClass().getDeclaredConstructor(long.class, int.class)  
        }

五) 現(xiàn)在回到第 2 步驟,發(fā)現(xiàn) PlatformDependent.useDirectBufferNoCleaner () 在 jdk 高版本下默認值是 false。那么每次申請直接內(nèi)存都是通過 ByteBuffer.allocateDirect 來創(chuàng)建。那么到這個時候就已經(jīng)定位到相關根因了,通過 ByteBuffer.allocateDirect 來申請直接內(nèi)存,如果內(nèi)存不足的時候會強制系統(tǒng) System.Gc (),并且會同步等待 DirectByteBuffer 通過 Cleaner 的虛引用回收內(nèi)存。下面是 ByteBuffer.allocateDirect 預占內(nèi)存(reserveMemory)的關鍵代碼。大概邏輯是 觸達申請的最大的直接內(nèi)存 -> 判斷是否有相關的對象在 gc 回收 -> 沒有在回收則主動觸發(fā) System.gc () 來觸發(fā)回收 -> 在同步循環(huán)最多等待 MAX_SLEEPS 次數(shù)看是否有足夠的直接內(nèi)存。整個同步等待邏輯在親測在 jdk17 版本最多能 1 秒以上。

所以最根本原因:如果這個時候我們的 netty 的消費者 EventLoop 處理消費因為申請直接內(nèi)存在達到最大內(nèi)存的場景,那么就會導致有大量的任務消費都會同步去等待申請直接內(nèi)存上。并且如果沒有足夠的的直接內(nèi)存,那么就會成為大面積的消費阻塞。

  
static void reserveMemory(long size, long cap) {  
  
    if (!MEMORY_LIMIT_SET && VM.initLevel() >= 1) {  
        MAX_MEMORY = VM.maxDirectMemory();  
        MEMORY_LIMIT_SET = true;  
    }  
  
    // optimist!  
    if (tryReserveMemory(size, cap)) {  
        return;  
    }  
  
    final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();  
    boolean interrupted = false;  
    try {  
  
        do {  
            try {  
                refprocActive = jlra.waitForReferenceProcessing();  
            } catch (InterruptedException e) {  
                // Defer interrupts and keep trying.  
                interrupted = true;  
                refprocActive = true;  
            }  
            if (tryReserveMemory(size, cap)) {  
                return;  
            }  
        } while (refprocActive);  
  
        // trigger VM's Reference processing  
        System.gc();  
  
        int sleeps = 0;  
        while (true) {  
            if (tryReserveMemory(size, cap)) {  
                return;  
            }  
            if (sleeps >= MAX_SLEEPS) {  
                break;  
            }  
            try {  
                if (!jlra.waitForReferenceProcessing()) {  
                    Thread.sleep(sleepTime);  
                    sleepTime <<= 1;  
                    sleeps++;  
                }  
            } catch (InterruptedException e) {  
                interrupted = true;  
            }  
        }  
  
        // no luck  
        throw new OutOfMemoryError  
            ("Cannot reserve "  
             + size + " bytes of direct buffer memory (allocated: "  
             + RESERVED_MEMORY.get() + ", limit: " + MAX_MEMORY +")");  
  
    } finally {  
        if (interrupted) {  
            // don't swallow interrupts  
            Thread.currentThread().interrupt();  
        }  
    }  
}

六) 雖然我們看到了阻塞的原因,但是為什么 jdk8 下為什么就不會阻塞從 4 步驟中看到 java 9 以下是設置了 DIRECT_BUFFER_CONSTRUCTOR 的,因此采用的是 PlatformDependent.allocateDirectNoCleaner 進行內(nèi)存分配。以下是具體的介紹和關鍵代碼

步驟一:申請內(nèi)存前:通過全局內(nèi)存計數(shù)器DIRECT_MEMORY_COUNTER,在每次申請內(nèi)存的時候調(diào)用 incrementMemoryCounter 增加相關的 size,如果達到相關 DIRECT_MEMORY_LIMIT (默認是 - XX:MaxDirectMemorySize) 參數(shù)則直接拋出異常,而不會去同步 gc 等待導致大量耗時。。

步驟二:分配內(nèi)存 allocateDirectNoCleaner: 是通過 unsafe 去申請內(nèi)存,再用構(gòu)造器DIRECT_BUFFER_CONSTRUCTOR通過內(nèi)存地址和大小來構(gòu)造 DirectBuffer。釋放也可以通過 unsafe.freeMemory 根據(jù)內(nèi)存地址來釋放相關內(nèi)存,而不是通過 java 自帶的 cleaner 來釋放內(nèi)存。

public static ByteBuffer allocateDirectNoCleaner(int capacity) {  
    assert USE_DIRECT_BUFFER_NO_CLEANER;  
  
    incrementMemoryCounter(capacity);  
    try {  
        return PlatformDependent0.allocateDirectNoCleaner(capacity);  
    } catch (Throwable e) {  
        decrementMemoryCounter(capacity);  
        throwException(e);  
        return null;    }  
}  
  
private static void incrementMemoryCounter(int capacity) {  
    if (DIRECT_MEMORY_COUNTER != null) {  
        long newUsedMemory = DIRECT_MEMORY_COUNTER.addAndGet(capacity);  
        if (newUsedMemory > DIRECT_MEMORY_LIMIT) {  
            DIRECT_MEMORY_COUNTER.addAndGet(-capacity);  
            throw new OutOfDirectMemoryError("failed to allocate " + capacity  
                    + " byte(s) of direct memory (used: " + (newUsedMemory - capacity)  
                    + ", max: " + DIRECT_MEMORY_LIMIT + ')');  
        }  
    }  
}  
  
static ByteBuffer allocateDirectNoCleaner(int capacity) {  
  return newDirectBuffer(UNSAFE.allocateMemory(Math.max(1, capacity)), capacity);  
}  
  

經(jīng)過上述的源碼分析,已經(jīng)看到了根本原因,就是 ByteBuffer.allocateDirect gc 同步等待直接內(nèi)存釋放導致消費能力嚴重不足導致的,并且在最大直接內(nèi)存不足的情況下,大面積的消費阻塞耗時在申請直接內(nèi)存,導致消費 WriteTask 能力接近于 0,內(nèi)存從而無法下降

總結(jié)

1. 流程圖: a743f9a8-5096-11ee-a25d-92fbcf53809c.png 2. 直接原因:

跨數(shù)據(jù)中心同步數(shù)據(jù)單 channel 管道同步數(shù)據(jù)能力不足,導致 tcp 環(huán)阻塞。從而導致 netty eventLoop 的消費 WriteTask 任務 (WriteAndFlush) 中的 write 能力大于 flush 能力,因此申請的大量的直接內(nèi)存存放在 ChannelOutboundBuffer#unflushedEntry 鏈表中沒法 flush。

3. 根本原因:

netty 在 jdk 高版本需要手動添加 jvm 參數(shù) -add-opens=java.base/java.nio=ALL-UNNAMED 和 - io.netty.tryReflectionSetAccessible 來開啟采用直接調(diào)用底層 unsafe 來申請內(nèi)存,如果不開啟那么 netty 申請內(nèi)存采用 ByteBuffer.allocateDirect 來申請直接內(nèi)存,如果 EventLoop 消費任務申請的直接內(nèi)存達到最大直接內(nèi)存場景,那么就會導致有大量的任務消費都會同步去等待申請直接內(nèi)存上。并且如果沒有釋放足夠的直接內(nèi)存,那么就會成為大面積的消費阻塞,也同時導致大量的對象累積在 netty 的無界隊列 MpscUnboundedArrayQueue 中。

4. 反思與定位問題慢的原因:

默認同步數(shù)據(jù)這里不會是系統(tǒng)瓶頸,沒有加上 lowWaterMark 和 highWaterMark 水位線的判斷(socketChannel.isWritable ()),如果同步數(shù)據(jù)達到系統(tǒng)瓶頸應該提前能感知到拋出異常。

同步數(shù)據(jù)的時候調(diào)用 writeAndFlush 應該加上相關的異常監(jiān)聽器(以下代碼 2),若果能提前感知到異常 OutOfMemoryError 那么更方便排查到相關問題。

(1)ChannelFuture writeAndFlush(Object msg)  
(2)ChannelFuture writeAndFlush(Object msg, ChannelPromise promise);

jdk17 下監(jiān)控系統(tǒng)看到的非堆內(nèi)存監(jiān)控并未與系統(tǒng)實際使用的直接內(nèi)存統(tǒng)計一致,導致開始定位問題無法定位到直接內(nèi)存已經(jīng)達到最大值,從而并未往這個方案思考。

相關引用的中間件底層通信也是依賴于 netty 通信,如果有類似的數(shù)據(jù)同步也可能會觸發(fā)類似的問題。特別 ump 在高版本和 titan 使用 netty 的時候是進行了 shade 打包的,并且相關的 jvm 參數(shù)也被修改,雖然不會觸發(fā)該 bug,但是也可能導致觸發(fā)系統(tǒng) gc。

ump高版本:jvm參數(shù)修改(低版本直接采用了底層socket通信,未使用netty和創(chuàng)建ByteBuffer) io.netty.tryReflectionSetAccessible->ump.profiler.shade.io.netty.tryReflectionSetAccessible  
  
titan:jvm參數(shù)修改:io.netty.tryReflectionSetAccessible->titan.profiler.shade.io.netty.tryReflectionSetAccessible  

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • cpu
    cpu
    +關注

    關注

    68

    文章

    11080

    瀏覽量

    217116
  • 數(shù)據(jù)中心

    關注

    16

    文章

    5230

    瀏覽量

    73529
  • TCP
    TCP
    +關注

    關注

    8

    文章

    1402

    瀏覽量

    81060
  • 內(nèi)存計算

    關注

    1

    文章

    15

    瀏覽量

    12240

原文標題:jdk17下netty導致堆內(nèi)存瘋漲原因排查

文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    分享一種內(nèi)存泄漏定位排查技巧

    常見的泄漏方式在嵌入式開發(fā)中,經(jīng)常會使用malloc,free分配釋放內(nèi)存,稍不小心就可能導致內(nèi)存一點點地泄露,直至
    發(fā)表于 12-17 08:13

    用rt_memheap_init分配內(nèi)存初始化失敗是何原因?怎么解決?

    用rt_memheap_init分配內(nèi)存,一到初始化任務分配內(nèi)存的時候就會出現(xiàn)問題請教一是什么原因
    發(fā)表于 02-13 14:18

    花旗:這五個原因或?qū)⑼苿犹O果股票明年

    據(jù)花旗研究(Citi Research)稱,由于五個重要原因,蘋果股票將在2017年?;ㄆ熘厣杲o予蘋果股票“買入”評級。
    發(fā)表于 12-14 10:43 ?302次閱讀

    比特幣背后的四個原因以及是否存在騙局的分析

    比特幣的造成了一種經(jīng)濟學困惑。數(shù)年內(nèi)超萬倍的漲幅令人震驚錯愕。
    的頭像 發(fā)表于 12-26 13:37 ?4544次閱讀

    什么是內(nèi)存?內(nèi)存是如何分配的?

    在一般的編譯系統(tǒng)中,內(nèi)存的分配方向和棧內(nèi)存是相反的。當棧內(nèi)存從高地址向低地址增長的時候,內(nèi)存
    的頭像 發(fā)表于 07-05 17:58 ?1w次閱讀

    netty推送消息接口及實現(xiàn)

    學過 Netty 的都知道,Netty 對 NIO 進行了很好的封裝,簡單的 API,龐大的開源社區(qū)。深受廣大程序員喜愛?;诖吮疚姆窒硪?b class='flag-5'>下基礎的 netty 使用。實戰(zhàn)制作一個
    的頭像 發(fā)表于 11-02 16:14 ?1780次閱讀

    一步步解決長連接Netty服務內(nèi)存泄漏

    線上應用長連接 Netty 服務出現(xiàn)內(nèi)存泄漏了!真讓人頭大
    的頭像 發(fā)表于 04-27 14:06 ?1592次閱讀
    一步步解決長連接<b class='flag-5'>Netty</b>服務<b class='flag-5'>內(nèi)存</b>泄漏

    什么是內(nèi)存?存儲方式是什么樣的?

    只有在內(nèi)存里面才會發(fā)生內(nèi)存泄漏的問題,在棧內(nèi)存中不會發(fā)生內(nèi)存泄漏。因為棧內(nèi)存在自動分配空間之后
    的頭像 發(fā)表于 06-22 10:29 ?1472次閱讀
    什么是<b class='flag-5'>堆</b><b class='flag-5'>內(nèi)存</b>?存儲方式是什么樣的?

    glibc導致內(nèi)存泄露的排查過程

    本文記錄一次glibc導致內(nèi)存泄露的排查過程。
    的頭像 發(fā)表于 09-01 09:43 ?1076次閱讀
    glibc<b class='flag-5'>導致</b>的<b class='flag-5'>堆</b>外<b class='flag-5'>內(nèi)存</b>泄露的<b class='flag-5'>排查</b>過程

    程序內(nèi)存分區(qū)中的與棧

    (Heap)與棧(Stack)是開發(fā)人員必須面對的兩個概念,在理解這兩個概念時,需要放到具體的場景,因為不同場景,與棧代表不同的含義。一般情況
    的頭像 發(fā)表于 11-11 16:21 ?1200次閱讀
    程序<b class='flag-5'>內(nèi)存</b>分區(qū)中的<b class='flag-5'>堆</b>與棧

    JDK11升級JDK17最全實踐

    2021年9月14日,Oracle發(fā)布了可以長期支持的JDK17版本,那么從JDK11到JDK17,到底帶來了哪些特性呢?亞毫秒級的ZGC效果到底怎么樣呢?值得我們升級嗎?而且升級過程會遇到哪些問題呢?帶著這些問題,本篇文章將帶
    的頭像 發(fā)表于 11-17 10:36 ?2051次閱讀
    <b class='flag-5'>JDK</b>11升級<b class='flag-5'>JDK17</b>最全實踐

    java內(nèi)存溢出排查方法

    Java內(nèi)存溢出(Memory overflow)是指Java虛擬機(JVM)中的內(nèi)存無法滿足對象分配的需求,導致程序拋出OutOfMemoryError異常。
    的頭像 發(fā)表于 11-23 14:46 ?3937次閱讀

    Java怎么排查oom異常

    據(jù)量的應用中。要排查OOM異常,需要經(jīng)過以下幾個步驟: 理解OOM異常的原因:OOM異常通常有以下幾個原因內(nèi)存泄露、內(nèi)存溢出、
    的頭像 發(fā)表于 12-05 13:47 ?1624次閱讀

    JDK11升級JDK17最全實踐干貨來了

    解決你的問題。 上篇文章給大家?guī)砹?b class='flag-5'>JDK8升級JDK11的最全實踐,相信大家閱讀后已經(jīng)對JDK11有了比較深入的了解。2021年9月14日,Oracle發(fā)布了可以長期支持的JDK17
    的頭像 發(fā)表于 06-25 14:50 ?1279次閱讀
    <b class='flag-5'>JDK</b>11升級<b class='flag-5'>JDK17</b>最全實踐干貨來了

    鉍金屬:中低溫焊錫膏中的鉍金屬何去何從?及其在戰(zhàn)爭中的應用探索

    探討鉍金屬背景,中低溫焊錫膏中鉍金屬的未來走向,并探索鉍金屬在戰(zhàn)爭領域的應用可能性。一、鉍金屬對中低溫焊錫膏的影響中低溫焊錫膏因其
    的頭像 發(fā)表于 03-07 13:43 ?723次閱讀
    鉍金屬<b class='flag-5'>瘋</b><b class='flag-5'>漲</b>:中低溫焊錫膏中的鉍金屬何去何從?及其在戰(zhàn)爭中的應用探索