JVM內存不足致使進程死掉. Native memory allocation (mmap) failed to maphtml
一臺服務器上部署不少JAVA進程已是微服務的常態,但也有些坑。java
背景,測試服務器上的一些JAVA進程忽然掛掉,查看call back的日誌發現以下:linux
1spring 2ubuntu 3服務器 4微服務 5oop 6測試 7ui 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
很明顯是因爲服務器的內存不足形成
內存不夠用分兩種狀況
推測:內存不夠用分兩種狀況
推測 1, JAVA程序使用的內存申請超出了JVM分配的, 此類只會拋出
java.lang.OutOfMemoryError: Java heap space,JAVA進程是不會有影響,下次也能夠繼續接受請求提供服務
推測 2, JVM嘗試去像操做系統申請一塊內存超出系統的可以使用(RSS)內存時, 此時linux會結束JAVA進程,並拋出如上錯誤。
這種場景也常見: 如在一臺16G內存的服務器上跑着兩個服務,兩個服務同時啓動各自分配10G內存,由於JVM的垃圾回收機制通常狀況下是不會有問題,能正常服務,當兩個服務同時須要用到的內存超出16G時,將會被linux幹掉一個服務.
(注: JVM啓動時,經過-Xmx等參數分配的內存只會影響到VIRT ,詳見上一篇博客《JAVA進程和linux內存間的大小關係》
證明:
去證明是最重要的, 上面的都是個人推測
一臺內存是1G的linux服務器
total used free shared buffers cached Mem: 984 119 864 0 2 20 -/+ buffers/cache: 97 886 Swap: 2044 45 1999
物理內存+swap內存 在 3G左右 (886+1999)
加入JAVA程序,由於是要觀察JAVA的內存超出是否會終止JAVA的進程,故思路以下設計
1,用一個線程去申請分配內存
2,主線程不停報告存活狀態
程序以下
package org.hejinbin.memory.test; import java.io.IOException; /** * 用於演示內存不足致使JAVA進程退出, 注意:輸入的size勿致使超出int (1024 * 1024 * size) * * @author 何錦彬 QQ 277803242(包子) 2016.12.29 */ public class Test { public static void main(String[] args) throws IOException, InterruptedException { new Thread(new Runnable() { public void run() { try { //接收測試內存的大小,單位m byte[] byteSize = new byte[50]; System.out.print("input want to allocation memory:"); int temp = System.in.read(byteSize); String sizeStr = new String(byteSize, 0, temp); int size = Integer.parseInt(sizeStr.trim()); System.out.println(1024 * 1024 * size); byte[] bt = new byte[1024 * 1024 * size]; System.out.println("succ..allocation: " + size + "m"); //阻30分,防止垃圾回收 Thread.sleep(1000 * 60 * 30); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); while (true) { //1分鐘後報告 Thread.sleep(1000 * 60); System.out.println(Thread.currentThread().getId() + ": i'm alive"); } } }
證明推測1:
運行程序,輸入1000 (這裏只要超過了年齡代內存其實就會拋出異常)
輸出 alive, 證實了推測1,使用內存超出了並不會致使JAVA進程死掉
證明推測2:
打開窗口1 , 運行,輸入
root@ubuntu:/home/hejinbin# java -Xmx3048m -Xms3048m org.hejinbin.memory.test.Test
input want to allocation memory:
打開窗口2 , 運行,輸入
root@ubuntu:/home/hejinbin# java -Xmx3048m -Xms3048m org.hejinbin.memory.test.Test
input want to allocation memory:
而後在窗口1輸入1500
運行以下:
input want to allocation memory:1500
succ..allocation: 1500m
而後在窗口2,輸入1500
input want to allocation memory:1500
succ..allocation: 1500m
此時發現窗口1的JAVA進程被殺掉了,完整以下
root@ubuntu:/home/hejinbin# java -Xmx3048m -Xms3048m org.hejinbin.memory.test.Test
input want to allocation memory:1500
succ..allocation: 1500m
Killed
證明了推測2
結論: 現在微服務流行(趁點熱度)。不少進程同時在一臺服務器上跑, 必須注意,分配給JAVA的內存只和必定在服務器的可用內存以內。否則頗有可能忽然被linux幹掉一個進程
最後還有個覺得,爲啥個人進程被killed以後,並無產生hs_err_pid*.log的日誌呢?