前言:JVM中除了程序计数器,其他的区域都有可能会发生内存溢出。

0.什么是内存溢出

当程序需要申请内存的时候,由于没有足够的内存,此时就会抛出OutOfMemoryError,这就是内存溢出。

1.内存泄漏和内存溢出区别与联系

  • 内存泄漏:系统分配的内存没有被回收。
  • 内存溢出:分配的内存空间超过系统内存。

2.内存泄漏的原因分析

 

jvm由5大块组成:堆,栈,本地方法栈,程序计数器,方法区。栈它的主要记录方法的执行和对象的引用。堆则存在真正的引用的对象。

内存泄漏是由于使用不当,把一部分内存“丢掉了”,导致这部分内存不可用。

当在堆中创建了对象,后来没有使用这个对象了,又没有把整个对象的相关引用设为null。此时垃圾收集器会认为这个对象是需要的,就不会清理这部分内存。这就会导致这部分内存不可用。

所以内存泄漏会导致可用的内存减少,进而会导致内存溢出。

3. JVM垃圾回收机制思想

就是从栈出发(root),遍历对象的引用,在遍历堆里面的引用对象,因为栈中的对象的引用执行完毕就删除,所以我们就可以通过栈中的对象的引用,查找到堆中没有被指向的对象,这些对象即为不可到达对象,对其进行垃圾回收。

4.内存溢出的原因分析

内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出。如果出现这种现象可行代码排查:

  1. 是否App中的类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串。如public static int i = 0; //public static String str;
  2. 是否App中使用了大量的递归或无限递归(递归中用到了大量的建新的对象)
  3. 是否App中使用了大量循环或死循环(循环中用到了大量的新建的对象)
  4. 检查App中是否使用了向数据库查询所有记录的方法。即一次性全部查询的方法,如果数据量超过10万多条了,就可能会造成内存溢出。所以在查询时应采用“分页查询”。
  5. 检查是否有数组,List,Map中存放的是对象的引用而不是对象,因为这些引用会让对应的对象不能被释放。会大量存储在内存中。
  6. 检查是否使用了“非字面量字符串进行+”的操作。因为String类的内容是不可变的,每次运行"+"就会产生新的对象,如果过多会造成新String对象过多,从而导致JVM没有及时回收而出现内存溢出。

如:

String s1 = "My name";
String s2 = "is";
String s3 = "xiaomanong";
String str = s1 + s2 + s3 +.........;

这是会容易造成内存溢出的

但是String str = "My name" + " is " + " xuwei" + " nice " + " to " + " meet you"; //但是这种就不会造成内存溢出。因为这是”字面量字符串“,在运行"+"时就会在编译期间运行好。不会按照JVM来执行的。

在使用String,StringBuffer,StringBuilder时,如果是字面量字符串进行"+"时,应选用String性能更好;如果是String类进行"+"时,在不考虑线程安全时,应选用StringBuilder性能更好。

5.常见的四种内存溢出情况

  1. 堆溢出(OutOfMemoryError:java heap space)
  2. 持久代溢出(OutOfMemoryError: PermGen space)
  3. 栈溢出(StackOverflowError)
  4. OutOfMemoryError:unable to create native thread

1)堆溢出:JVM Heap :java.lang.OutOfMemoryError: Java heap space

JVM在启动的时候会自动设置JVM Heap的值, 可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。Heap的大小是Young Generation 和Tenured Generaion 之和。在JVM中如果98%的时间是用于GC,且可用的Heap size 不足2%的时候将抛出此异常信息。

解决方法 :手动设置JVM Heap(堆)的大小。

2)持久代溢出:PermGen space : java.lang.OutOfMemoryError: PermGen space

PermGen space的全称是Permanent Generation space,是指内存的永久保存区域。为什么会内存溢出,这是由于这块内存主要是被JVM存放Class和Meta信息的,Class在被Load的时候被放入PermGen space区域,它和存放Instance的Heap区域不同,sun的 GC不会在主程序运行期对PermGen space进行清理,所以如果你的APP会载入很多CLASS的话,就很可能出现PermGen space溢出。一般发生在程序的启动阶段。

解决方法 : 通过-XX:PermSize和-XX:MaxPermSize设置永久代大小即可。

3)栈溢出: java.lang.StackOverflowError : Thread Stack space

栈溢出了,JVM依然是采用栈式的虚拟机,这个和C和Pascal都是一样的。函数的调用过程都体现在堆栈和退栈上了。调用构造函数的 “层”太多了,以致于把栈区溢出了。 通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要 1K的空间(这个大约相当于在一个C函数内声明了256个int类型的变量),那么栈区也不过是需要1MB的空间。通常栈的大小是1-2MB的。通俗一点讲就是单线程的程序需要的内存太大了。 通常递归也不要递归的层次过多,很容易溢出。

解决方法 :1:修改程序。2:通过 -Xss: 来设置每个线程的Stack大小即可。

4)OutOfMemoryError:unable to create native thread

OutOfMemoryError:unable to create native thread:字面意思是内存溢出:无法创建新的线程。字面意思已经很明显了,出现这种情况的原因基本下面2点:

  1. 程序创建的线程数超过操作系统的限制。
  2. JVM占用的内存太多,导致创建线程的内存空间太小。

我们都知道操作系统对每个进程的内存是有限制的,我们启动Jvm,相当于启动了一个进程,假如我们一个进程占用了4G的内存,那么通过下面的公式计算出来的剩余内存就是建立线程栈的时候可以用的内存。 线程栈总可用内存=4G-(-Xmx的值)- (-XX:MaxPermSize的值)- 程序计数器占用的内存 通过上面的公式我们可以看出,-Xmx 和 MaxPermSize的值越大,那么留给线程栈可用的空间就越小,在-Xss参数配置的栈容量不变的情况下,可以创建的线程数也就越小。因此如果是因为这种情况导致的unable to create native thread,

解决方法:1:增大进程所占用的总内存。2:减少-Xmx或者-Xss来达到创建更多线程的目的。

5)小结

  1. 栈内存溢出:程序所要求的栈深度过大导致。
  2. 堆内存溢出: 分清 内存泄露还是 内存容量不足。泄露则看对象如何被 GC Root 引用。不足则通过 调大 -Xms,-Xmx参数。
  3. 持久带内存溢出:Class对象未被释放,Class对象占用信息过多,有过多的Class对象。
  4. 无法创建本地线程:总容量不变,堆内存,非堆内存设置过大,会导致能给线程的内存不足。

补充:阿里巴巴内存溢出面试题

下面哪种情况会导致持久区jvm堆内存溢出():

A. 循环上万次的字符串处理

B. 在一段代码内申请上百M甚至上G的内存

C. 使用CGLib技术直接操作字节码运行,生成大量的动态类

D. 不断创建对象

解答:AC

解析:AC是持久带,B直接内存也就是堆外内存,D堆内存。

参考书籍:

《深入理解Java虚拟机》 (第二版) 周志明 著;

关于JVM内存溢出的原因分析及解决方案探讨的更多相关文章

  1. 5种JVM垃圾收集器特点和8种JVM内存溢出原因

    先来看看5种JVM垃圾收集器特点 一.常见垃圾收集器 现在常见的垃圾收集器有如下几种: 新生代收集器: Serial ParNew Parallel Scavenge 老年代收集器: Serial O ...

  2. JVM内存溢出分析java.lang.OutOfMemoryError: Java heap space

    JVM内存溢出查询java.lang.OutOfMemoryError: Java heap space查出具体原因分为几个预备步骤 1.在运行java程序是必须设置jvm -XX:+HeapDump ...

  3. jvm内存溢出分析

    概述 jvm中除了程序计数器,其他的区域都有可能会发生内存溢出 内存溢出是什么? 当程序需要申请内存的时候,由于没有足够的内存,此时就会抛出OutOfMemoryError,这就是内存溢出 内存溢出和 ...

  4. Tomcat中JVM内存溢出及合理配置及maxThreads如何配置(转)

    来源:http://www.tot.name/html/20150530/20150530102930.htm Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚 ...

  5. Java抛出OutOfMemoryError:Java heap space堆内存溢出错误的分析方案

    抛出堆内存溢出的错误一定要记得保留现场环境(导出堆内存信息到文件),否则如果无法进行分析,并从根本上解决问题,下次很有可能还会出现. 第一步:导出堆转储文件 我们可以使用Jdk自带的jmap工具.使用 ...

  6. Tomcat中JVM内存溢出及合理配置

    Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对Java JVM有关内存方面的知识 ...

  7. JVM内存溢出及合理配置

    Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.Tomcat的内存溢出本质就是JVM内存溢出,所以在本文开始时,应该先对Java JVM有关内存方面的知识 ...

  8. 定位JVM内存溢出问题思路总结

    JVM的内存溢出问题,是个常见而有时候有非常难以定位的问题.定位内存溢出问题常见方法有很多,但是其实很多情况下可供你选择的有效手段非常有限.很多方法在一些实际场景下没有实用价值.这里总结下我的一些定位 ...

  9. 牛客网Java刷题知识点之内存溢出和内存泄漏的概念、区别、内存泄露产生原因、内存溢出产生原因、内存泄露解决方案、内存溢出解决方案

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

随机推荐

  1. Java多线程(六):wait(),notify()和notifyAll()

    wait(),notify()和notifyAll()介绍 1.wait() 使当前线程等待,直到另一个线程调用notify(),notifyAll()或者中断,当前线程调用wait()之前必须持有锁 ...

  2. shell脚本常见错误一二三

    1.$'\r': 未找到命令的解决 2.: 不是有效的标识符h: 3.cd "$path"/webapps/ROOT 不能正常进入ROOT文件夹,$path并未与后面的字符结合起来 ...

  3. Bzoj 2281 [Sdoi2011]黑白棋 题解

    2281: [Sdoi2011]黑白棋 Time Limit: 3 Sec  Memory Limit: 512 MBSubmit: 592  Solved: 362[Submit][Status][ ...

  4. Java编程思想:XML

    /* 本次实验需要在www.xom.nu上下载XOM类库 */ import nu.xom.*; import java.io.BufferedOutputStream; import java.io ...

  5. 使用jqueryUI实现自由调整表格列宽

    今天项目中需要插入表格,用Excel表格调整列宽时,想怎么拖就怎么拖,于是乎就让插入的表格也这么让人舒服.网上查找许久,没找到好用的方案.最后发现jQuery UI中的resizable()方法可以实 ...

  6. 个人永久性免费-Excel催化剂功能第103波-批量打开多文件或多链接

    有时简单的东西,却带来许多的便利,为了让大家可以记住并容易找寻到此功能,也将这么简单的功能归为一波,反正已经100+波了,也无需为了凑功能文章而故意罗列一些小功能带忽悠性地让人觉得很强大. 使用场景 ...

  7. 基于TCP协议的套接字编程

    06.26自我总结 1.关于Socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在 ...

  8. TensorFlow笔记-可视化Tensorboard

    可视化Tensorboard •数据序列化-events文件 TensorBoard 通过读取 TensorFlow 的事件文件来运行 •tf.summary.FileWriter('/tmp/ten ...

  9. vue教程(三)-slot\keep-alive的使用

    一.slot其实就是填坑操作,父组件传递dom结构,是vue提供的一种内置组件(组件知识请查看上篇博客内容) 写法:<slot></slot> 例子: var child = ...

  10. php框架内的数据库操作(微擎,tp,yii2)

    微擎数据库操作 关键字 查询 pdo_get pdo_getcolumn pdo_getall pdo_getslice pdo_fetchcolumn pdo_fetchall 示例: array ...