這里圖片加載不了,原文請訪問:原文鏈接
公司的項目,這幾天添加了一個統計功能, 本地測試沒太大問題,上線后有一個問題,具體現象描述如下:
- 統計首頁接口大約有5-6個,也就是同時需要訪問6個接口拿首頁數據
- 這些接口瀏覽器訪問會隨機的,偶爾的出現跨域錯誤,提示CROS。但偶爾又能全部正常訪問
- 本地測試沒有問題CROS問題
基于以上描述,首先想到可能nginx會有問題,因為線上和測試環境就只加了一層轉發。而測試環境沒有這個問題, 于是直接暴露線上服務端口訪問,故障依舊。
這里沒太想明白為啥是cros錯誤,對比了下options請求響應,都是正常請求響應的,響應數據也是正確的。所以這個問題暫記下
但是本地啟動為什么沒有CROS問題呢,看了下線上啟動腳本,線上啟動有添加堆大小限制的啟動命令(限制為512MB)。本地同步添加,果然問題就在本地復現了。
訪問瀏覽器提示跨域時,服務后臺日志如下:
14:50:41.003 [http-nio-8985-exec-60] ERROR o.a.c.h.Http11NioProtocol - [log,175] - Failed to complete processing of a request
java.lang.OutOfMemoryError: Java heap space
14:50:41.210 [http-nio-8985-exec-58] ERROR o.a.c.h.Http11NioProtocol - [log,175] - Failed to complete processing of a request
java.lang.OutOfMemoryError: Java heap space
14:50:41.211 [http-nio-8985-exec-60] ERROR o.a.t.u.n.NioEndpoint - [log,175] - Error running socket processor
java.lang.NullPointerException: Cannot invoke "java.nio.ByteBuffer.limit(int)" because "this.byteBuffer" is nullat org.apache.coyote.http11.Http11InputBuffer.recycle(Http11InputBuffer.java:262)at org.apache.coyote.http11.Http11Processor.recycle(Http11Processor.java:1418)at org.apache.coyote.AbstractProtocol$ConnectionHandler.release(AbstractProtocol.java:1085)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1060)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)at java.base/java.lang.Thread.run(Thread.java:842)
14:50:41.211 [http-nio-8985-exec-58] ERROR o.a.t.u.n.NioEndpoint - [log,175] - Error running socket processor
java.lang.NullPointerException: Cannot invoke "java.nio.ByteBuffer.limit(int)" because "this.byteBuffer" is nullat org.apache.coyote.http11.Http11InputBuffer.recycle(Http11InputBuffer.java:262)at org.apache.coyote.http11.Http11Processor.recycle(Http11Processor.java:1418)at org.apache.coyote.AbstractProtocol$ConnectionHandler.release(AbstractProtocol.java:1085)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:1060)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)at java.base/java.lang.Thread.run(Thread.java:842)
堆溢出,我擦。第一時間想的就是哪里內存泄漏了? 導出堆空間,分析下內存。 這里可以看到有一個對象堆占用特別多
接下來看下堆中各個對象占用情況:
這里可以看到 bytes 數組占用太大,有點不正常。 繼續跟進去看看誰在引用這些數組。
把這個字節數組導出來,看看是寫什么。 這里面只有http請求頭,而且后面很多都是空。 大小125MB.
繼續跟蹤字節數組被誰持有
這里可以看到字節數組被一個http11InputBuffer
對象的inputBuffer
持有, 而inputBuffer
里面headerBufferSize
屬性,這個屬性值等于131072000
也就是前面的 125MB
這個headerbuffer怎么這么大啊,谷歌搜索下,這個buffer是用來裝http請求的header數據內容,也就是說http每次請求就需要申請125MB的空間,怪不得請求會報堆棧溢出。
再看了下文章,這個屬性可以通過 max-http-request-header-size
屬性進行配置。
所以接下來就簡單了,項目中搜索這個配置。有人配置為:max-http-request-header-size: 131072000
換算下來 1GB。 我的天
這也太大了,調整為10MB吧。 重啟項目,問題消失。
結語就是,繞了一大圈,這個跨域錯誤居然是內存泄漏,這個提示真的有方向性誤導啊。哈哈