java内存泄漏
一、什么是内存泄漏
开发中,都能遇到或者听过两种关于java内存的异常情况:内存溢出(out of memory)和内存泄漏(memory leak)。
内存溢出指的是程序需要申请新的内存时,没有足够大小的内存空间供其使用。常见类型:
1、java.lang.OutOfMemoryError: Java heap space 堆内存溢出 解决办法:通过-Xmn(最小值)–Xms(初始值) -Xmx(最大值)参数手动设置 Heap(堆)的大小
2、 java.lang.StackOverflowError 栈溢出 解决办法:通过Xss参数调整大小
3、 java.lang.OutOfMemoryError: PermGen space 解决办法:通过MaxPermSize参数设置PermGen space大小
内存泄漏指的是程序申请内存后,当不再使用时,本该被回收却始终无法释放或是不能及时的释放已申请的内存空间。内存泄漏,如果数量庞大,最终是会导致内存溢出的。
对用户来说,内存泄漏并不会产生什么危害。程序代码、运行对用户是完全透明的,真正的危害性在于内存泄漏可能导致的最终的内存溢出,程序崩溃终止。
这里,java开发人员一般会有疑问:既然java存在GC,为什么还会发生内存泄漏?
简单说说GC的回收:
java GC会监控所有堆中创建的对象的运行状况,监控对象是否可达(从GC Roots根开始向下搜索),如果对象不可达,则其就可以被GC回收。GC由jvm自动执行,不可人为干预(System.gc()方法只是建议jvm去执行回收动作,并不能确定一定会即时的去执行)
内存泄漏为什么发生:
实际的开发过程中,可能会存在着无用但可达的对象,这些对象不能被GC回收,所以就导致了内存泄漏的产生。
二、java中案例
1、静态集合类中存储对象
static List<Object> list = new ArrayList<>(); public static void main(String[] args) { for(int i =0; i<10; i++){ Object object = new Object(); list.add(object); object = null; } }
静态集合类中,循环申请对象放入集合中。后面仅仅是对新申请的对象置null,并不能引起GC对于这个对象的回收,因为集合类仍然对其保持着引用,
也就是可达的(list引用指向的内存空间中存在指向 Object 对象的引用)。如果后面的程序中,不再使用集合list,则这就产生了内存溢出。一般好的习惯,不使用的集合clear,然后置为null。
2、单例模式
单例的生命周期和应用程序是一样长的,所以单例程序中,如果持有对外部对象的引用的话,那么这个外部对象是不能被回收的,则会导致内存泄漏的产生。
3、一些提供close的资源未关闭导致内存泄漏
数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接必须手动close,否则是不能被回收的。