• OOM 问题分类


    • 线程数太多

    • 打开太多文件

    • 内存不足

    线程数太多:

    | 报错信息

    pthread_create (1040KB stack) failed: Out of memory

    查看系统对每个进程的线程数限制:

    cat /proc/sys/kernel/threads-max

    不同设备的 threads-max 限制是不一样的,有些厂商的低端机型 threads-max 比较小,容易出现此类 OOM 问题

    查看当前进程运行的线程数:

    cat proc/{pid}/status

     当线程数超过 /proc/sys/kernel/threads-max 中规定的上限时就会触发 OOM。

    | 线程优化

    ①禁用 new Thread

    解决线程过多问题,传统的方案是禁止使用 new Thread,统一使用线程池,但是一般很难人为控制, 可以在代码提交之后触发自动检测,有问题则通过邮件通知对应开发人员。

    不过这种方式存在两个问题:

    • 无法解决老代码的 new Thread

    • 对于第三方库无法控制

    ②无侵入性的 new Thread 优化

    Java 层的 Thread 只是一个普通的对象,只有调用了 start 方法,才会调用 native 层去创建线程。

    所以理论上我们可以自定义 Thread,重写 start 方法,不去启动线程,而是将任务放到线程池中去执行,为了做到无侵入性,需要在编译期通过字节码插桩的方式,将所有 new Thread 字节码都替换成 new 自定义 Thread。

    步骤如下:

    创建一个 Thread 的子类叫 ShadowThread 吧,重写 start 方法,调用自定义的线程池 CustomThreadPool 来执行任务。

    public class ShadowThread extends Thread {

        @Override
        public synchronized void start() {
            Log.i("ShadowThread", "start,name="+ getName());
            CustomThreadPool.THREAD_POOL_EXECUTOR.execute(new MyRunnable(getName()));
        }

        class MyRunnable implements Runnable {

            String name;
            public MyRunnable(String name){
                this.name = name;
            }

            @Override
            public void run() {
                try {
                    ShadowThread.this.run();
                    Log.d("ShadowThread","run name="+name);
                } catch (Exception e) {
                    Log.w("ShadowThread","name="+name+",exception:"+ e.getMessage());
                    RuntimeException exception = new RuntimeException("threadName="+name+",exception:"+ e.getMessage());
                    exception.setStackTrace(e.getStackTrace());
                    throw exception;
                }
            }
        }
    }

     打开太多文件

    错误信息

    E/art: ashmem_create_region failed for 'indirect ref table': Too many open files
    Java.lang.OutOfMemoryError: Could not allocate JNI Env





    /proc/pid/limits 描述着 linux 系统对每个进程的一些资源限制

     如果没有 root 权限,可以通过 ulimit -n 命令查看 Max open files,结果是一样的。

    ulimit -n
    内存不足

    | 堆栈信息

    图片

    | 重温 JVM 内存结构

    JVM 在运行时,将内存划分为以下 5 个部分:

    • 方法区:存放静态变量、常量、即时编译代码

    • 程序计数器:线程私有,记录当前执行的代码行数,方便在 cpu 切换到其它线程再回来的时候能够不迷路

    • Java 虚拟机栈:线程私有,一个 Java 方法开始和结束,对应一个栈帧的入栈和出栈,栈帧里面有局部变量表、操作数栈、返回地址、符号引用等信息

    • 本地方法栈:线程私有,跟 Java 虚拟机栈的区别在于 这个是针对 native 方法

    • 堆:绝大部分对象创建都在堆分配内存

    内存不足导致的 OOM,一般都是由于 Java 堆内存不足,绝大部分对象都是在堆中分配内存,除此之外,大数组、以及 Android3.0-7.0 的 Bitmap 像素数据,都是存放在堆中。

    Java 堆内存不足导致的 OOM 问题,线上难以复现,往往比较难定位到问题,绝大部分设备都是 8.0 以下的,主要也是由于 Android 3.0-7.0 Bitmap 像素内存是存放在堆中导致的。

  • 相关阅读:
    项目构建之maven篇:2.HelloWorld项目构建过程
    求最大子段和的一些算法
    多线程编程(四)--线程同步
    SICP 解题集 — SICP 解题集
    函数式编程很难,这正是你要学习它的原因 | 外刊IT评论网
    haskell,lisp,erlang你们更喜欢哪个?
    欧舒丹 L'Occitane 活力清泉保湿面霜
    段子
    宽带中国战略_百度百科
    brutal是什么意思_brutal在线翻译_英语_读音_用法_例句_海词词典
  • 原文地址:https://www.cnblogs.com/KL2016/p/16257135.html
Copyright © 2020-2023  润新知