docker 內(nèi)運(yùn)行的java服務(wù)
#進(jìn)入docker
#docker 配置支持jmap命令
#0巷嚣、docker-compose.yml 新增節(jié)點(diǎn)cap_add
cap_add:
- ALL
#1拐揭、找到對應(yīng)的docker id
docker ps|grep yourserver
#2慢叨、進(jìn)入docker 內(nèi)部
docker exec -it e8c96f1fb92e sh
#3、使用jps 找到對應(yīng)的java進(jìn)程 id
jps
#4、jmap 命令的使用
jmap pid
jmap -clstats pid
jmap -head pid
jmap -heap pid
jmap -histo:live pid
jmap -finalizerinfo pid
#5旺嬉、內(nèi)存dump和分析
#5.1 導(dǎo)出整個JVM 中內(nèi)存信息
jmap -dump:format=b,file=heapdump.hprof pid
#5.2 把docker的文件復(fù)制到主機(jī)
docker cp e8c96f1fb92e:/app/yourserver.hprof /data/log/
#把主機(jī)文件復(fù)制到docker內(nèi)
docker cp /root/yourserver.hprof e8c96f1fb92e:/app/
#5.3 把文件下載到本地使用jprofile分析
#6荆忍、使用jstat命令查看jvm的GC情況
jstat -gc 30996 3000
#即:每3秒一次顯示進(jìn)程號為30996的java進(jìn)程的GC情況
#或使用命令:jstat -gcutil 30996 3000
#發(fā)現(xiàn)大對象
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread$ConnectionFinalizerPhantomReference
https://github.com/brettwooldridge/HikariCP/issues/1473
https://stackoverflow.com/questions/6981564/why-must-the-jdbc-driver-be-put-in-tomcat-home-lib-folder/7198049#7198049
JDBC drivers register themselves in the JVM-wide singleton [`DriverManager`](http://download.oracle.com/javase/6/docs/api/java/sql/DriverManager.html) which is shared by *all* web apps. If you have the same (as in class name) JDBC driver register twice from two different web apps, this might cause your problem. This is even more problematic if your web apps use different versions of the same JDBC driver.
Also, putting JDBC drivers into Tomcat's lib folder will help prevent memory leaks when you redeploy your web app without restarting Tomcat, e.g. if you just put a new WAR file into Tomcat's webapps folder:
We can produce the phenomenon by setting the maxLifetime to a relatively small value like a minute(all other configs are using the default value). Using tools like VisualVM, we can see an obvious increasement of `AbandonedConnectionCleanupThread$ConnectionFinalizerPhantomReference` objects.
其他類型內(nèi)存泄漏
HashMap 的 put 過程中有可能出現(xiàn)了死循環(huán)問題(圖中 java.util.HashMap $Entry 0x2add6d992cb8 和 0x2add6d992ce8 的 next 引用形成循環(huán))。
查閱相關(guān)文檔定位這屬于典型的并發(fā)使用的場景錯誤 (http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6423457) 囊蓝,簡要的說就是 HashMap 本身并不具備多線程并發(fā)的特性饿悬,在多個線程同時 put 操作的情況下,內(nèi)部數(shù)組進(jìn)行擴(kuò)容時會導(dǎo)致 HashMap 的內(nèi)部鏈表形成環(huán)形結(jié)構(gòu)聚霜,從而出現(xiàn)死循環(huán)狡恬。
If a HashMap is used in a concurrent setting with insufficient synchronization, it is possible for the data structure to get corrupted in such a way that infinite loops appear in the data structure and thus get() could loop forever.
詳情參考:
[https://developer.51cto.com/art/202004/614586.htm](https://developer.51cto.com/art/202004/614586.htm)