一、概念
1. 内存泄漏:对象使用完之后,没有按照预期被GC回收,一直留在内存中
2. 内存溢出:大量对象一直留在内存中,导致内存不够用(OOM),影响正常的程序运行
二、内存泄漏的场景
1. 内存中数据量太大,比如一次性从数据库中取出来太多数据
2. 静态集合类中对对象的引用,在使用完后未清空(只把对象设为null,而不是从集合中移除),使JVM不能回收,即内存泄漏
3. 静态方法中只能使用全局静态变量,而如果静态变量又持有静态方法传入的参数对象的引用,会引起内存泄漏
4. 代码中存在死循环,或者循环过多,产生过多的重复的对象
5. JVM启动参数内存值设置过小
a. 堆内存:JVM默认为64M,-Xms堆的最小值, -Xmx堆的最大值,OutOfMemoryError: java heap space
b. 栈内存:-Xss,StackOverflowError,栈太深
c. 永久代内存:-XX:PermSize,-XX:MaxPermSize,OutOfMemoryError: PermGen space,加载的类过多
6. 监听器:addXXListener,没有remove
7. 各种连接没有关闭:例如数据库连接、网络连接
8. 单例模式:如果单例对象持有外部对象的引用,那么外部对象将不会被回收,引起内存泄漏
9. 一个类含有静态变量,这个类的对象就无法被回收
10. ThreadLocal
三、解决思路
1. 修改JVM启动参数,直接增加内存
2. 检查错误日志
3. 检查代码中有没有一次性查出数据库所有数据
4. 检查代码中是否有死循环
5. 检查代码中循环和递归是否产生大量重复对象
6. 检查List/Map等集合,是否未清除
7. 使用内存查看工具
四、代码优化
1. 主动释放无用的对象
2. 尽量使用StringBuilder代替String
3. 尽量少用静态变量,因为静态变量是类的,GC不会回收
4. 避免创建大对象和同时创建多个对象,例如数组,因为数组的长度是固定的
5. 对象池技术
五、JVM堆内存溢出后,其他线程可否继续工作?
1. 当前线程OOM后,如果终止,会发生GC,其他线程可以继续工作
2. 如果线程OOM后,没有终止,其他线程也会OOM