問題描述node
Linux內存使用量超過閾值,使得Java應用程序無可用內存,最終致使程序崩潰。即便在程序沒有掛掉時把程序停掉,系統內存也不會被釋放。shell
找緣由的過程緩存
這個問題已經困擾我好幾個月了,分析過好屢次都沒有找到緣由,網上查了一下該問題其餘人也都遇到過,不過並無什麼好的解決方案,由於項目一直沒有上線,每次當內存不足時致使程序崩潰都是重啓服務就行了,索性也就沒花太多的時間來找問題。如今項目立刻上線了,不能在出現程序崩潰的狀況了,何況仍是前置系統,更不能出現任何問題。tomcat
最開始一直認爲是程序的緣由致使內存泄漏,使用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的內存app
三條指令:ui
syncthis
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)。.net
注意:在執行這三條命令以前必定要先執行sync命令(描述:sync 命令運行 sync 子例程。若是必須中止系統,則運行sync 命令以確保文件系統的完整性。sync 命令將全部未寫的系統緩衝區寫到磁盤中,包含已修改的 i-Node、已延遲的塊 I/O 和讀寫映射文件)rest
解決方案(手動)
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命令
解決方案(自動)
一、編寫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
二、使用crontab -e命令編輯當前用戶的crontab
0 6 * * * /usr/local/tomcat/sztFileFront/bin/freemem.sh
定時任務編寫參考:http://www.jb51.net/article/15008.htm
三、重啓crond服務
/sbin/service crond restart
四、查看crond服務是否重啓成功
/sbin/service crond status
最後,問題解決。我設定的定時任務是天天早上6點執行一次freemem.sh腳本