死磕内存篇2 --JAVA进程是怎么突然挂掉的

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了死磕内存篇2 --JAVA进程是怎么突然挂掉的相关的知识,希望对你有一定的参考价值。

JVM内存不足导致进程死掉. Native memory allocation (mmap) failed to map

一台服务器上部署很多JAVA进程已经是微服务的常态,但也有些坑。
 
 
背景,测试服务器上的一些JAVA进程突然挂掉,查看call back的日志发现如下:
 
# There is insufficient memory for the Java Runtime Environment to continue. 
# Native memory allocation (mmap) failed to map 1786867712 bytes for committing reserved memory. 
# Possible reasons: 
# The system is out of physical RAM or swap space 
# In 32 bit mode, the process size limit was hit 
# Possible solutions: 
# Reduce memory load on the system 
# Increase physical memory or swap space 
# Check if swap backing store is full 
# Use 64 bit Java on a 64 bit OS 
# Decrease Java heap size (-Xmx/-Xms) 
# Decrease number of Java threads 
# Decrease Java thread stack sizes (-Xss) 
# Set larger code cache with -XX:ReservedCodeCacheSize= 
# This output file may be truncated or incomplete. 
# 
# Out of Memory Error (os_linux.cpp:2673), pid=28610, tid=139813184919296 
# 
# JRE version: Java(TM) SE Runtime Environment (8.0_40-b26) (build 1.8.0_40-b26) 
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.40-b25 mixed mode linux-amd64 compressed oops) 
# 

  

很明显是由于服务器的内存不足造成

 

内存不够用分两种情况

 

 推测:内存不够用分两种情况
 
推测 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 , 运行,输入
[email protected]:/home/hejinbin# java -Xmx3048m -Xms3048m org.hejinbin.memory.test.Test 

input want to allocation memory:

 
打开窗口2 , 运行,输入
[email protected]:/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进程被杀掉了,完整如下
 
[email protected]:/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的日志呢? 

以上是关于死磕内存篇2 --JAVA进程是怎么突然挂掉的的主要内容,如果未能解决你的问题,请参考以下文章

死磕算法之汇总篇

死磕前端javascript知识点详细讲解 • 第2篇《作用域与作用域链》

死磕Java虚拟机-性能调优实战篇

UNIX再学习 -- 死磕内存管理

死磕 java集合之终结篇

死磕MyCat使用篇之第一篇