Java中的OutOfMemoryError
发布日期:2021-07-01 01:42:10 浏览次数:2 分类:技术文章

本文共 2586 字,大约阅读时间需要 8 分钟。

转载自  

引子:今天在<Sharding-JDBC官方群>里有个哥们称“不连sjdbc不会把内存吃光,连sjdbc跑一会就把内存吃光”,倍感诧异,我们已经用sj很久了,一直未发现sj吃内存的情况,遂向他要了测试程序。测试之后才发现他所谓的吃内存是报了“java.lang.OutOfMemoryError: unable to create new native thread”的错,殊不知创建线程不使用JVM Memory,这个报错不是程序吃内存,跟sjdbc更是没有关系。他的数据库连接池maxActive=30,开线程较多时(我开了10000个),前面的线程没有释放数据库连接,后面的线程就要等待,造成线程积压,最终无法创建新线程,自然“unable to create new native thread”。所以还需要扫盲式的向诸位普及一下Java中的内存溢出。

1.java.lang.OutOfMemoryError: unable to create new native thread

就是上面例子里面提到的情况。Java中当你创建线程的时候,JVM会在JVM 内存创建一个Thread同时创建一个系统本地线程,这个系统线程使用的内存不是JVM memory,而是系统剩余的内存,所以遇到这种情况有时候需要通过“减少内存”的手段来解决(指减少堆内存)。通常情况下我们有个计算公式来估算能创建线程数的多少:countOfThreads=(processMaxMemory - JVM Memory - otherOsMemory) / (threadStackSize) ,这里的MaxProcessMemory是指一个进程可以占用的最大内存,比如在32位window下是2G,otherOsMemory是保留的操作系统内存,threadStackSize是通过-Xss参数设置的线程栈大小,当然,还会受到系统最大可创建的线程数量的限制。

2.Java.lang.OutOfMemoryError: Java heap space

这种是我们最常见的Java堆溢出,我们配置JVM参数时使用-Xms配置堆的最小值,使用-Xmx配置堆的最大值(通常会将-Xms和-Xmx配置成相同,避免堆的自动扩展)。Java堆中存放的是对象实例,当Java堆中对象达到限制就会产生内存溢出,常见的情况有:死循环往一个List中添加对象,一次性将大文件或者从数据库查询的大批量数据加载到内存中。对于这种情况,我们通过JVM配置-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Data/domains/trans-account/server1/logs来保存内存快照,然后用相关内存分析工具进行分析。

3. java.lang.OutOfMemoryError: PermGen space

 PermGen space的全称是Permanent Generation space,是内存的永久保存区域,主要存储虚拟机加载的类、常量、静态变量等元数据信息,垃圾收集行为在这个区域几乎不出现。对于有大量JSP、大量使用CGLib字节码增强的应用,会很容易出现这种错误,出现问题时,我们经常通过增大-XX:MaxPermSize参数来解决。

4. java.lang.OutOfMemoryError: GC overhead limit exceeded

GC overhead limt exceed检查是Hotspot VM定义的一个策略,通过统计GC时间来预测是否要OOM了,提前抛出异常,防止OOM发生。官方对此的定义是:“并行/并发回收器在GC回收时间过长时会抛出OutOfMemroyError。过长的定义是,超过98%的时间用来做GC并且回收了不到2%的堆内存。用来避免内存过小造成应用不能正常工作。”这种情况跟第二种情况有重合的地方,也是通过检查是否有死循环或者占用大内存的代码,当然,可以使用-XX:-UseGCOverheadLimit(默认是+UseGCOverheadLimit)来去除GC时间的限制。

5. java.lang.OutOfMemoryError: nativeGetNewTLA

这个错误只有在JRockitJVM上才会遇到,大家工作环境中如果都默认使用Hotspot的话应该不会遇到这个问题,所以如果大家不感兴趣完全可以不care(真的,私以为,没有业务场景基础的技术意淫都是耍流氓)。TLA是Thread Local Area(线程本地空间)的简写,线程本地空间是多线程程序里面为了更有效的进行内存分配而建立的缓存。每一个线程都有一份自己的缓存,当这个线程要创建对象的时候,就在这上面分配。如果你有很多线程同时并发,又要创建大量的对象,可能会出现这个问题。

6.java.lang.OutOfMemoryError: Requested array size exceeds VM limit 

这个错误比较少见,除非你真的new了一个非常非常大的数组(比如,一个亿?YOU CAN TRY~)当出现这种情况,与其去增大JVM的-Xmx,不如好好看下你的代码逻辑是不是出现了什么问题。

7.java.lang.OutOfMemoryError: request xxxxxx(size) bytes for xxxxxxx(reason). Out of swap space? 

额,这种情况我真没遇到过,不过我们可以了解一下:它是当虚拟机向本地操作系统申请内存失败时抛出的。这和你用完了堆或者持久化中的内存的情况有些不同。这个错误通常是在你的程序已经逼近平台限制的时候产生的。这个信息告诉你的是你可能已经用光了物理内存以及虚拟内存了。由于虚拟内存通常是用磁盘作为交换分区,因此你最先想到的解决方法可能是先增加交换分区的大小。

8.java.lang.OutOfMemoryError: xxxx<reason> xxxx<stack trace>(Native method)

这种报错是从native method中抛出的,不是JVM执行的方法,如果遇到这种情况,咳,自求多福吧。

转载地址:https://maokun.blog.csdn.net/article/details/80662199 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:深入JVM——OOM异常解析
下一篇:测试OOM异常

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年04月07日 03时11分45秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章