• 记一个有趣的Java OOM!


    原文:https://my.oschina.net/u/1462914/blog/1630086

    引言

      熟悉Java的童鞋,应该对OOM比较熟悉。该类问题,一般都比较棘手。因为造成此类问题的原因有很多。今天就分享一个非常有意思的案例。(说实话。这个问题,我也是前两天才遇到的。花了不少时间来分析。觉得非常有意思,记录在此。大神勿喷!)

    问题场景

    重启应用时,调试到给MQ发消息时。有如下错误:

    Exception in thread "Thread-4" java.lang.OutOfMemoryError: unable to create new native thread
        at java.lang.Thread.start0(Native Method)
        at java.lang.Thread.start(Thread.java:717)
        at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:957)
        at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1378)
        at org.apache.activemq.thread.PooledTaskRunner.wakeup(PooledTaskRunner.java:81)
        at org.apache.activemq.transport.failover.FailoverTransport.reconnect(FailoverTransport.java:757)
        at org.apache.activemq.transport.failover.FailoverTransport.start(FailoverTransport.java:344)
        at org.apache.activemq.transport.TransportFilter.start(TransportFilter.java:58)
        at org.apache.activemq.transport.TransportFilter.start(TransportFilter.java:58)

    一开始,以为是系统磁盘,或者内存占满导致。通过top命令查看系统信息。均属于正常范围。正在尝试寻找其他方案的同时。在SSH中输入命令是。出现以下错误:

    $ bash: fork: Resource temporarily unavailable

    出现上述问题后:非常明显的提示来资源不足导致。

    经分析:是由于当前系统使用的线程数大于ulimit中的max_user_processes的数量导致。

    Linux ulimit 参数

      上面说到了,与系统(Linux)中的ulimit参数有关。ulimit 是用来限制系统资源的。
    其中包括:

    1. max memory size (最大内存大小)。

    2. open files(打开文件数)。

    3. max user processes(最大用户进程数)
      等等。

    系统性能优化常常会优化此参数。

    (有兴趣的童鞋可以自行了解更多)

    ulimit 常用命令:

    1. 显示open files

    $ ulimit -n
    65535

    其中 ulimit -n 显示的结果为: open files的数值。

    2. 显示当前用户的最大进程数

    $ ulimit -u
    60000

    其中ulimit -u 显示的结果为: max_user_processes额值。

    2. 显示ulimit 所有属性

    $ ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 127399
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 65535
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 10240
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 60000
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

    其中:

    1. open files 表示打开文件的最大数。

    2. max user processes 当前用户打开能打开的最大进程数。

    (一) 修改 open files 数量

    其中open files 属性, 可以在/etc/security/limits.conf文件中修改。在文件末尾添加。如下所示代码:

    *               soft    nofile          65535
    *               hard    nofile          65535

    其中:

    1. nofile 表示 open files

    2. nproc  对应的属性为: max_user_processes

    3. 其中 65535 为演示数字。请按照环境的实际情况进行调整。

    (二) 修改 max_user_processes 数量

    其中 max_user_processes属性,可以在/etc/security/limits.d/90-nproc.conf路径下进行修改。
    修改如下:

    *          soft    nproc     60000
    root       soft    nproc     unlimited

    需要注意的是:

    1. max_user_processes中最大的值为: 60000。
      如果设置超过60000,则默认为最大值。例如: 设置 655535,则会为60000。

    2. 执行上述步骤后。退出当前会话。重新连接即可生效!在修改之前连接的会话,需要重新连接,才能看到新的配置。

    查看系统资源方法

    1. 查看当前系统使用的进程数。      

      我们可以使用: ps aux|wc -l或者ps -ef|wc -l命令来查看当前正在使用的进程数。
    如下所示:

    $ ps aux|wc -l
    309

    有时通过ps aux|wc -l 命令查看得到的数据少于max_user_processes 的值。
    也出现:

    $ bash: fork: Resource temporarily unavailable`

    这是因为一个进程中可以包含多个线程导致。

    2. 查看指定进程数中的线程数。  

      当我们知道了的进程ID(PID)后,
    也可以通过如下方法查看当前进程中有多少个线程:
    命令:

    $ cat /proc/<pid>/status

    案例如下:

    andy@andyqian:/java$ cat /proc/11723/status
    Name:    java
    State:    S (sleeping)
    Tgid:    11723
    Ngid:    0
    Pid:    11723
    PPid:    2434
    TracerPid:    0
    Uid:    1000    1000    1000    1000
    Gid:    1000    1000    1000    1000
    FDSize:    128
    Groups:    4 24 27 30 46 108 124 1000 
    Threads:    28
    SigQ:    0/47456
    Seccomp:    0
    Cpus_allowed:    ff
    Cpus_allowed_list:    0-7
    Mems_allowed:    00000000,00000001
    Mems_allowed_list:    0
    voluntary_ctxt_switches:    88
    nonvoluntary_ctxt_switches:    3

    其中:

    1. Threads:28 就表示该进程中,一个有28个线程。

    2. 由于篇幅原因,以上删除了部分信息。

    3. 如何查看应用的进程   &nbsp;可能有童鞋不知道如何查看应用的进程数,这里给个简单的案例:
    例如查看一个名命为tomcat01的tomcat。我们可以通过如下命令查看:

    ps -aux|grep tomcat01

    如下所示:

    andy@andyqian:/java$ ps -aux|grep tomcat01
    andy     11723  0.5  1.0 6484560 127292 pts/1

    其中: 11723 对应的就是tomcat01的进程ID。

  • 相关阅读:
    Navicat Premium 12 破解汉化64位 windows版本
    Tkinter入门简明教程
    python tkinter-消息框、对话框、文件对话框
    python中ui自动化selenium方法封装分享
    Windows利用EasyWebSvr起web服务
    Windows安装mysql服务端
    北京个人所得税纳税记录打印
    Java并发之ReentrantReadWriteLock源码解析(二)
    Java并发之ReentrantReadWriteLock源码解析(一)
    Java并发之Semaphore源码解析(二)
  • 原文地址:https://www.cnblogs.com/shihaiming/p/8520692.html
Copyright © 2020-2023  润新知