转自: https://blog.csdn.net/oscaryue/article/details/72967448

近期在App监测平台上发现如下错误信息:

java.lang.OutOfMemoryError: pthread_create (stack size 16384 bytes) failed: Try again
    at java.lang.VMThread.create(VMThread.java)
    at java.lang.Thread.start(Thread.java:1029)
    at com.migu.uem.statistics.page.b.e(b.java)
    at com.migu.uem.statistics.page.b.a(b.java)
...
java.lang.OutOfMemoryError: pthread_create (stack size 16384 bytes) failed: Try again(Heap Size=15488KB, Allocated=12634KB)
    at java.lang.VMThread.create(VMThread.java)
    at java.lang.Thread.start(Thread.java:1063)
...
java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
    at java.lang.Thread.nativeCreate(Thread.java)
    at java.lang.Thread.start(Thread.java:1076)
    at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:920)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1338)
...
内存溢出(OOM)了?是啊,明明白白写着“java.lang.OutOfMemoryError”。然而,有没有注意到错误信息里都有关于stack字样?对,这是由于栈内存不足造成的,而不是常见的堆内存溢出。程序猿们经常上的网站StackOverFlow终于出现在程序里了!其实,准确地说,此时并没有发生栈溢出,而是连栈都没有分配成功 :P
从调用栈上可以发现,都是在本地方法创建线程的时候出现的:pthread_create。有兴趣的同学可以去了解一下linux的API。点我点我
堆内存相信程序猿们都了解,这里大概说一下栈(stack)是干什么用的:保存局部变量、保存现场、保存函数参数……栈内存的运作方式也真的是按照栈的方式:先进后出,将临时变量逐个压栈,然后按照相反的顺序弹出。
典型的栈溢出会出现在没有写好退出条件的递归调用,相信不少人在学生时期算法课都写过类似这样的代码:

void f(int i) {
    f(++i);
}
整个函数并没有分配任何内存,但却会迅速耗尽栈内存。栈溢出的后果有时很严重,在某些系统上甚至会让系统悄无声息地重启,别问我怎么知道的T_T
栈内存还有一个作用,就是保存线程的现场——给线程留个“快照”(snapshot)。每个处理器在某个时间点只能有1个线程在执行,所有这个处理器上执行的线程按照操作系统的调度算法在自己的时间片内执行。
刚才说到局部变量都保存在栈上,我们先来考虑一下下面这个问题:有2个函数walk()、sit():

void walk() {
    int speed;
    int direction;
...
    return;
}

void sit() {
    int position;
    int duration;
...
    return;
}
现在有2个线程thread1、thread2,分别调用walk()和sit()。当thread1调用walk()并执行后,speed和direction被分配到栈上,恰好在walk()返回前线程切换了,thread2开始执行sit(),并在栈上分配了position、duration变量。这时栈长这样:

duration
position
direction
speed
接下来thread1又被调度了,执行到了return,要清除现场了,弹出栈上分配的内存。然而,栈顶的内存并不是thread1分配的!这下尴尬了。。。把栈顶元素释放了,等thread2继续执行就傻了;释放自己分配的内存?栈不允许釜底抽薪,只能移动栈顶指针。实际上并不会出现这种尴尬的场面,因为每个线程都会有一个自己的栈 :D
盗一张图:

可以看到,线程的栈内存是相互独立的。有人会问,那么在栈上分配的内存就是线程安全的、不用考虑同步吗?是的!
对于java,分配线程栈资源是在调用start()后开始,会调用本地方法创建线程并获取相关资源,然后调用线程的run()方法(说句题外话,不要直接调用run()!这样只会在当前线程执行)。
这就不难理解为什么会在创建线程时出现栈溢出了。操作系统通常不会限制线程数,但栈内存是有限制的。上面错误信息中有:
(stack size 16384 bytes)
(1040KB stack)
这些就是线程栈的大小,跟系统设置有关。有的很小16384字节;有的就大多了1040K字节。注意,这个并不是进程栈大小,进程栈可以通过ulimit -s或ulimit -a查看:

shell@hwmt7:/ $ ulimit -a
time(cpu-seconds)    unlimited
file(blocks)         unlimited
coredump(blocks)     0
data(KiB)            unlimited
stack(KiB)           8192
lockedmem(KiB)       64
nofiles(descriptors) 1024
processes            13326
flocks               unlimited
sigpending           13326
msgqueue(bytes)      819200
maxnice              40
maxrtprio            0
resident-set(KiB)    unlimited
address-space(KiB)   unlimited
这种栈溢出比较少见,想要体验一下的同学可以这么做:
1)写一个运行了就不会轻易退出的线程——比如在run()里写个死循环
2)再写一个循环,不断创建上面线程的实例,并调用start()
3)静静等待吧,如果你的设备线程栈比较小,500多个线程就挂了(比如华为mate 7);如果比较大,可能要3000多个(比如魅族m1)
亲测可用,成果展示:

06-07 17:49:47.209 4229-1169/com.oscaryue.testapp W/libc: pthread_create failed: clone failed: Try again
06-07 17:49:47.210 4229-1169/com.oscaryue.testapp E/aoc: Throwing OutOfMemoryError "pthread_create (1040KB stack) failed: Try again"
06-07 17:49:47.211 4229-1169/com.oscaryue.testapp W/System.err: java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
06-07 17:49:47.230 4229-1169/com.oscaryue.testapp W/System.err:     at java.lang.Thread.nativeCreate(Native Method)
06-07 17:49:47.230 4229-1169/com.oscaryue.testapp W/System.err:     at java.lang.Thread.start(Thread.java:1063)
06-07 17:49:47.230 4229-1169/com.oscaryue.testapp W/System.err:     at java.util.Timer$TimerImpl.<init>(Timer.java:192)
06-07 17:49:47.230 4229-1169/com.oscaryue.testapp W/System.err:     at java.util.Timer.<init>(Timer.java:365)
06-07 17:49:47.230 4229-1169/com.oscaryue.testapp W/System.err:     at java.util.Timer.<init>(Timer.java:384)
06-07 17:49:47.230 4229-1169/com.oscaryue.testapp W/System.err:     at java.util.Timer.<init>(Timer.java:391)
06-07 17:49:47.230 4229-1169/com.oscaryue.testapp W/System.err:     at com.oscaryue.testapp.MyTimer$1.run(MainActivity.java:52)
06-07 17:49:47.230 4229-1169/com.oscaryue.testapp W/System.err:     at java.lang.Thread.run(Thread.java:818)
06-07 17:49:47.235 4229-1169/com.oscaryue.testapp E/AndroidRuntime: FATAL EXCEPTION: Thread-7729
                                                                    Process: com.oscaryue.testapp, PID: 4229
                                                                    java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
                                                                        at java.lang.Thread.nativeCreate(Native Method)
                                                                        at java.lang.Thread.start(Thread.java:1063)
                                                                        at java.util.Timer$TimerImpl.<init>(Timer.java:192)
                                                                        at java.util.Timer.<init>(Timer.java:365)
                                                                        at java.util.Timer.<init>(Timer.java:384)
                                                                        at java.util.Timer.<init>(Timer.java:391)
                                                                        at com.oscaryue.testapp.MyTimer$1.run(MainActivity.java:52)
                                                                        at java.lang.Thread.run(Thread.java:818)
06-07 17:49:50.823 4229-4244/com.oscaryue.testapp W/aoc: Suspending all threads took: 5.334ms
06-07 17:49:51.072 4229-1169/com.oscaryue.testapp I/Process: Sending signal. PID: 4229 SIG: 9
现实中怎么会出现这样的OOM呢?总不能那么赤裸裸地写死循环吧?来来,老司机教你 :P
1)开个线程池,不要设置线程数上限,或者设置成max_int也行
2)巧妙地利用线程同步写个死锁,让线程池里的线程互相等待,永不结束
3)好啦,现在就可以悄悄扩展线程池了,OOM就在不远的前方
而且,触发这个OOM的是恰巧在临界点创建线程的倒霉蛋,作为罪魁祸首的你也不那么容易被揪出来,哈哈
玩笑了,说到最后,大家还是要避免这种问题的发生。

由一个stack OOM引发的血案相关推荐

  1. 一个“Spring轮子”引发的“血案”(4)

    事件的升级,国产技术社区中所存现出来的浮躁.世态炎凉,在我的一篇<80前>一文,终于引爆了出来. <80前>一文是一个长篇,是我吃这么20多年饭,读了不少书的一些所思.所误.所 ...

  2. 一个@Component注解引发的血案

    一个注解@Component引发的血案 首先,我们这个是用springboot架构来实现的业务 这是项目包结构和配置文件结构这是定时需要执行的任务 这是我执行PromoCodeCMCJob这个定时器的 ...

  3. 一个由正则表达式引发的血案

    阿里妹导读:周末快到了,今天为大家送上一篇很有意思的小文章,具有提神醒脑之功效.作者是来自阿里巴巴LAZADA产品技术部的申徒童鞋. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中 ...

  4. 转:一个Sqrt函数引发的血案

    转自:http://www.cnblogs.com/pkuoliver/archive/2010/10/06/1844725.html 源码下载地址:http://diducoder.com/sotr ...

  5. 一个Sqrt函数引发的血案

    我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来实现这个经常调用的函数呢? 虽然 ...

  6. 一个数字键盘引发的血案——移动端H5输入框、光标、数字键盘全假套件实现...

    https://juejin.im/post/5a44c5eef265da432d2868f6 为啥要写假键盘? 还是输入框.光标全假的假键盘? 手机自带的不用非得写个假的,吃饱没事干吧? 装逼?炫技 ...

  7. 一个缓存穿透引发的血案

    2010年9月23日,Facebook遭遇了迄今为止最严重的宕机事件之一,网站关闭了4个小时.为恢复工作,不得不让FB下线,影响了10亿用户. 在事后的故障报告中提到: 今天,我们修改了一个错误的配置 ...

  8. 一个时间字段引发的血案

    hi ,大家好,我是三天打鱼,两天晒网的小六六 前言 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger 种一棵树最好 ...

  9. 一个变量类型引发的血案

    想要用WebGL实现一个响应鼠标画点的程序.无奈一直出现: 比对了2天,逐字校对,最终找到了原因: gl_PointSize是浮点数....浮点...浮...扑街!! gl_PointSize = 1 ...

最新文章

  1. 运维企业专题(5)LVS高可用与负载均衡中篇——VS/DR模式配置详解
  2. 向基于Linux的Oracle RAC 10g集群添加新节点
  3. 开发中遇到的问题,以及笔记
  4. kubernetes log 流式数据处理
  5. java facade dao_java – 在Facade模式中放置用于创建namedQuer...
  6. matlab画一个局部放大的图中图
  7. Springboot集成cache的key生成策略
  8. Azure人工智能认知服务(AI·机器学习)
  9. MySQL保留关键字
  10. Objective-C基础3:内存管理续
  11. Scala是多范式编程语言
  12. 再论:男人有多大责任和感恩代表着有多大的驾驭能力和事业能力
  13. DB2数据库常用命令及查询
  14. 诗字辈大全:诗仙、诗圣、诗魔、诗佛、诗神、诗鬼、诗杰、诗狂、诗骨、诗家夫子、诗豪、诗囚、诗奴...
  15. 树莓派sd卡linux分区,树莓派安装了Kali系统的SD卡扩容问题(分区太小)解决办法...
  16. 这款萌到吐血的医疗无人机,速度惊人且支持空气动力充电
  17. linux离线安装sails,关于sails 初学者常见问题汇总(示例代码)
  18. 136 137 260只出现一次的数字【我亦无他唯手熟尔】
  19. centos彻底删除文件夹、文件命令
  20. textarea剩余可输入字数

热门文章

  1. 吐血推荐历史最全的蓝牙协议栈介绍
  2. 关于Vue的表单验证
  3. oppor7软件root,oppor7软件商店打不开怎么办
  4. JavaScript高级 |彻底搞懂原型对象
  5. python callable对象_Python中callable的理解?
  6. Java程序员用代码,计算最大公约数和最小公倍数小傅哥
  7. python使用urllib2_Python中urllib2总结
  8. Kettle教程(二):Kettle目录结构介绍
  9. 【Linux篇】sed命令详解
  10. 支付宝也来蹭NFT热点?完事后澄清:NFT不是代币,旨在保护知识产权