2019獨角獸企業重金招聘Python工程師標準>>>
問題描述
Linux內存使用量超過閾值,使得Java應用程序無可用內存,最終導致程序崩潰。即使在程序沒有掛掉時把程序停掉,系統內存也不會被釋放。
找原因的過程
這個問題已經困擾我好幾個月了,分析過好多次都沒有找到原因,網上查了一下該問題其他人也都遇到過,不過并沒有什么好的解決方案,因為項目一直沒有上線,每次當內存不足時導致程序崩潰都是重啟服務就好了,索性也就沒花太多的時間來找問題。現在項目馬上上線了,不能在出現程序崩潰的情況了,況且還是前置系統,更不能出現任何問題。
最開始一直認為是程序的原因導致內存泄漏,使用jdk自帶的jmap -F -dump:live,format=b,file=/usr/local/sztFront/logs/heapdump.bin命令輸出過幾次dump文件,通過MemoryAnalyzer分析,應用程序沒有耗內存過大的變量。后臺猜測是否日志輸出過多導致的,畢竟是前置系統,每天的報文量特別大,日志能到達5,6個G。所以把日志接收報文關了,日志大小馬上降下來了,每天200M。程序掛掉的時間變長了,原來差不多一周就掛掉了,現在可以達到兩周左右才掛掉,還是不行,沒有沖根本上解決問題。經過在網上搜索各種相關的問題,問題出現在Cached的值過大,導致系統沒有可以再分配的內存空間。Cached只要用來緩存文件的,經常讀寫的文件會被緩存到Cached中,可以增加讀寫效率,該功能是Linux系統內核提供的,從2.6.16以后的核心版本才提供,也就是老版的操作系統,如紅旗DC 5.0、RHEL 4.x之前的版本都沒有。這就可以解釋為什么我的項目總掛掉了,我的項目主要就是處理文件的,所以接收和下載的文件會被緩存起來,一直耗著內存不釋放,即使把程序停掉也不會釋放內存。最后找到了三條執行,可以清理cached的內存
三條指令:
sync
echo 1 > /proc/sys/vm/drop_caches
echo 2 > /proc/sys/vm/drop_caches
echo 3 > /proc/sys/vm/drop_caches
執行完這三條指令后通過free -m命令查看,free可用內存馬上增多,buff/cache列值變小,說明內存被釋放了,但是不能總是手動的執行這三條指令,所以最后寫了一個shell腳本,開啟Linux定時任務crond,每天早上檢查一次free內存,當小于4G時執行這三條命令(注:系統內容20G)。
注意:在執行這三條命令之前一定要先執行sync命令(描述:sync 命令運行 sync 子例程。如果必須停止系統,則運行sync 命令以確保文件系統的完整性。sync 命令將所有未寫的系統緩沖區寫到磁盤中,包含已修改的 i-Node、已延遲的塊 I/O 和讀寫映射文件)
解決方案(手動)
1. 修改/proc/sys/vm/drop_caches,釋放Slab占用的cache內存空間(參考drop_caches的官方文檔):
Writing to this will cause the kernel to drop clean caches, dentries and inodes from memory, causing that memory to become free.
To free pagecache:
* echo 1 > /proc/sys/vm/drop_caches
To free dentries and inodes:
* echo 2 > /proc/sys/vm/drop_caches
To free pagecache, dentries and inodes:
* echo 3 > /proc/sys/vm/drop_caches
As this is a non-destructive operation, and dirty objects are notfreeable, the user should run "sync" first in order to make sure allcached objects are freed.
This tunable was added in 2.6.16.
注意:在執行這三條命令前先執行sync命令
解決方案(自動)
1、編寫shell定時任務腳本freemem.sh
#! /bin/sh
used=`free -m | awk 'NR==2' | awk '{print $3}'`
free=`free -m | awk 'NR==2' | awk '{print $4}'`
echo "===========================" >> /app/memory/logs/mem.log
date >> /app/memory/logs/mem.log
echo "Memory usage before | [Use:${used}MB][Free:${free}MB]" >> /app/memory/logs/mem.log
if [ $free -le 4000 ] ; then
? ? ? ? ? ? ? ? sync && echo 1 > /proc/sys/vm/drop_caches
? ? ? ? ? ? ? ? sync && echo 2 > /proc/sys/vm/drop_caches
? ? ? ? ? ? ? ? sync && echo 3 > /proc/sys/vm/drop_caches
?? ??? ??? ??? ?used_ok=`free -m | awk 'NR==2' | awk '{print $3}'`
?? ??? ??? ??? ?free_ok=`free -m | awk 'NR==2' | awk '{print $4}'`
?? ??? ??? ??? ?echo "Memory usage after | [Use:${used_ok}MB][Free:${free_ok}MB]" >> /app/memory/logs/mem.log
? ? ? ? ? ? ? ? echo "OK" >> /app/memory/logs/mem.log
else
? ? ? ? ? ? ? ? echo "Not required" >> /app/memory/logs/mem.log
fi
exit 1
2、使用crontab -e命令編輯當前用戶的crontab
0 6 * * * /usr/local/tomcat/sztFileFront/bin/freemem.sh
定時任務編寫參考:http://www.jb51.net/article/15008.htm
3、重啟crond服務
/sbin/service crond restart
4、查看crond服務是否重啟成功
/sbin/service crond status
最后,問題解決。我設定的定時任務是每天早上6點執行一次freemem.sh腳本
?