日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

本文介紹了直接緩沖存儲(chǔ)器的處理方法,對大家解決問題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧!

問題描述

我需要從Web請求返回一個(gè)相當(dāng)大的文件。該文件的大小約為670MB。在大多數(shù)情況下,這可以很好地工作,但一段時(shí)間后會(huì)拋出以下錯(cuò)誤:

java.lang.OutOfMemoryError: Direct buffer memory
    at java.nio.Bits.reserveMemory(Bits.java:694) ~[na:1.8.0_162]
    at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) ~[na:1.8.0_162]
    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) ~[na:1.8.0_162]
    at sun.nio.ch.Util.getTemporaryDirectBuffer(Util.java:241) ~[na:1.8.0_162]
    at sun.nio.ch.IOUtil.read(IOUtil.java:195) ~[na:1.8.0_162]
    at sun.nio.ch.FileChannelImpl.read(FileChannelImpl.java:159) ~[na:1.8.0_162]
    at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:65) ~[na:1.8.0_162]
    at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:109) ~[na:1.8.0_162]
    at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:103) ~[na:1.8.0_162]
    at java.nio.file.Files.read(Files.java:3105) ~[na:1.8.0_162]
    at java.nio.file.Files.readAllBytes(Files.java:3158) ~[na:1.8.0_162]

我已將堆大小設(shè)置為4096MB,我認(rèn)為該大小應(yīng)該足以處理此類文件。此外,當(dāng)這個(gè)錯(cuò)誤發(fā)生時(shí),我使用jmap獲取堆轉(zhuǎn)儲(chǔ)來分析當(dāng)前狀態(tài)。我發(fā)現(xiàn)了兩個(gè)相當(dāng)大的字節(jié)[],這應(yīng)該是我想要返回的文件。但是堆的大小只有1.6 GB左右,還沒有達(dá)到配置的4 GB大小。

根據(jù)其他一些答案(https://stackoverflow.com/a/39984276/5126654),在一個(gè)類似的問題中,我嘗試在返回此文件之前運(yùn)行手動(dòng)GC。問題仍然存在,但現(xiàn)在只是零星的。問題在一段時(shí)間后出現(xiàn),但當(dāng)我再次厭倦運(yùn)行相同的請求時(shí),似乎垃圾收集已經(jīng)解決了導(dǎo)致問題的問題,但這是不夠的,因?yàn)閱栴}顯然仍然可能發(fā)生。是否有其他方法可以避免此內(nèi)存問題?

推薦答案

DirectByteBuffer管理的實(shí)際內(nèi)存緩沖區(qū)不在堆中分配。它們是使用UnSafe.allocateMemory分配的,它分配本機(jī)內(nèi)存和。因此,增加或減少堆大小無濟(jì)于事。

當(dāng)GC檢測到DirectByteBuffer不再被引用時(shí),將使用Cleaner釋放本機(jī)內(nèi)存。但是,這種情況發(fā)生在收集后階段,因此如果對直接緩沖區(qū)的需求/周轉(zhuǎn)太大,收集器可能跟不上。如果發(fā)生這種情況,您將獲得OOME。


您能對此做些什么?

AFAIK,您唯一可以做的就是強(qiáng)制更頻繁的垃圾回收。但這可能會(huì)對性能產(chǎn)生影響。我不認(rèn)為這是一個(gè)有保證的解決方案。

真正的解決方案是采取不同的方法。

您看到您正在從Web服務(wù)器提供大量非常大的文件,堆棧跟蹤顯示您正在使用Files::readAllBytes將它們加載到內(nèi)存中,然后(假設(shè))使用單個(gè)write發(fā)送它們。想必您這樣做是為了盡可能獲得最快的下載時(shí)間。這是一個(gè)錯(cuò)誤:

您占用了大量內(nèi)存(是垃圾收集器的倍數(shù),給垃圾收集器帶來了壓力。這導(dǎo)致了更多的GC運(yùn)行和偶爾的OOME。它還可能以各種方式影響服務(wù)器上的其他應(yīng)用程序。

傳輸文件的瓶頸可能是而不是從磁盤讀取數(shù)據(jù)的過程。(真正的瓶頸是通常通過網(wǎng)絡(luò)上的TCP流發(fā)送數(shù)據(jù),或?qū)?shù)據(jù)寫入客戶端的文件系統(tǒng)。)

如果您按順序讀取一個(gè)大文件,現(xiàn)代Linux操作系統(tǒng)通常會(huì)使用預(yù)讀大量磁盤塊,并將這些塊保存在(OS)緩沖區(qū)緩存中。這將減少您的應(yīng)用程序進(jìn)行的read系統(tǒng)調(diào)用的延遲。

因此,對于這種大小的文件,更好的方法是對文件進(jìn)行流式處理。要么分配一個(gè)大的(幾兆字節(jié))ByteBuffer并循環(huán)讀寫,使用Files::copy(...)(javadoc)復(fù)制文件,這應(yīng)該會(huì)為您負(fù)責(zé)緩沖。

(也可以選擇使用映射到Linux系統(tǒng)調(diào)用的內(nèi)容。這會(huì)將數(shù)據(jù)從一個(gè)文件描述符復(fù)制到另一個(gè)文件描述符,而不會(huì)將其寫入用戶空間緩沖區(qū)。)

這篇關(guān)于直接緩沖存儲(chǔ)器的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,

分享到:
標(biāo)簽:緩沖存儲(chǔ)器
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定