处理 Java 的“Cannot allocate memory”错误
今天在配置 DCA 服务器的时候,检验 java 版本的时候忽然遇到了一个 Cannot allocate memory 错误
[root@elcid-prod1 ~]# java -version
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00007ff55c5ea000, 4096, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 4096 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /root/hs_err_pid5138.log
查找了一下相关文档,发现这个错误的含义其实就是像它自己说的,没法分配内存了。
The problem is inherent with the way Java allocates memory when executing processes. When Java executes a process, it must fork() then exec(). Forking creates a child process by duplicating the current process. By duplicating the current process, the new child process will request approximately the same amount of memory as its parent process, essentially doubling the memory required. However, this does not mean all the memory allocated will be used, as exec() is immediately called to execute the different code within the child process, freeing up this memory. As an example, when Stash tries to locate git, the Stash JVM process must be forked, approximately doubling the memory required by Stash.
解决方案呢有两个,第一个是用别的方法(例如 posix_spawn)替换掉 Java 的 fork/exec 方法从而申请到内存,第二个是开启系统的 Over-commit,跳过系统的可用内存检查直接分配。
第一个方法比较麻烦,需要使用一个 custom JNI binding 去更改 Java 底层调用,所以先不尝试。
第二个方法比较简单,但可能会导致依赖 C 语言 malloc() 的程序出错。
总之先试试第二个吧,毕竟就是改下系统变量的事儿。
临时更改: echo 1 > /proc/sys/vm/overcommit_memory
永久更改: 编辑 /etc/sysctl.conf,修改参数 vm.overcommit_memory = 1,重启服务器或者用户重新登录
参考:http://bryanmarty.com/2012/01/14/forking-jvm/