纳尼,Java 不是自动管理内存吗?怎么可能会出现内存泄泄泄泄泄泄漏!html
Java 最牛逼的一个特性就是垃圾回收机制,不用像 C++ 须要手动管理内存,因此做为 Java 程序员很幸福,只管 New New New 便可,反正 Java 会自动回收过时的对象。。。java
那么 Java 都自动管理内存了,那怎么会出现内存泄漏,难道 Jvm 有 bug? 不要急,且听我慢慢道来。。git
先了解一下 Jvm 是怎么判断一个对象能够被回收。通常有两种方式,一种是引用计数法,一种是可达性分析。程序员
引用计数法:每一个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时能够回收。面试
这个办法看起来挺简单的,可是若是出现 A 引用了 B,B 又引用了 A,这时候就算他们都再也不使用了,但由于相互引用 计算器=1 永远没法被回收。工具
此方法简单,没法解决对象相互循环引用的问题。spa
可达性分析(Reachability Analysis):从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证实此对象是不可用的,那么虚拟机就判断是可回收对象。code
可达性分析能够解决循环引用的问题。cdn
那么 gc roots 对象是哪些呢htm
目前主流的虚拟机中大多使用可达性分析的方式来断定对象是否可被 GC 回收。
既然可达性分析好像已经很牛逼的样子了,怎么可能还会出现内存泄漏呢,那咱们再来看一下内存泄漏的定义。
内存泄露就是指一个再也不被程序使用的对象或变量一直被占据在内存中。
有可能此对象已经不使用了,可是还有其它对象保持着此对象的引用,就会致使 GC 不能回收此对象,这种状况下就会出现内存泄漏。
写一个程序让出现内存泄漏
①长生命周期的对象持有短生命周期对象的引用就极可能发生内存泄露,尽管短生命周期对象已经再也不须要,可是由于长生命周期对象持有它的引用而致使不能被回收。
public class Simple {
Object object;
public void method1(){
object = new Object();
//...其余代码
}
}
复制代码
这里的 object 实例,其实咱们指望它只做用于 method1() 方法中,且其余地方不会再用到它,可是,当method1()方法执行完成后,object 对象所分配的内存不会立刻被认为是能够被释放的对象,只有在 Simple 类建立的对象被释放后才会被释放,严格的说,这就是一种内存泄露。
解决方法就是将 object 做为 method1() 方法中的局部变量。
public class Simple {
Object object;
public void method1(){
object = new Object();
//...其余代码
object = null;
}
}
复制代码
固然你们有可能会想就这一个方法也不会有多大影响,但若是在某些项目中,一个方法在一分钟以内调用上万次的时候,就会出现很明显的内存泄漏现象。
②集合中的内存泄漏,好比 HashMap、ArrayList 等,这些对象常常会发生内存泄露。好比当它们被声明为静态对象时,它们的生命周期会跟应用程序的生命周期同样长,很容易形成内存不足。
下面给出了一个关于集合内存泄露的例子。
Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
Object o=new Object();
v.add(o);
o=null;
}
//此时,全部的Object对象都没有被释放,由于变量v引用这些对象。
复制代码
在这个例子中,咱们循环申请 Object 对象,并将所申请的对象放入一个 Vector 中,若是咱们仅仅释放引用自己,那么 Vector 仍然引用该对象,因此这个对象对 GC 来讲是不可回收的。
所以,若是对象加入到 Vector 后,还必须从 Vector 中删除,最简单的方法就是将 Vector 对象设置为 null。
以上两种是最多见的内存泄漏案例。固然还有一些内存泄漏的例子,这里就再也不一一例举了,感兴趣的同窗能够在网上找找资料。
不少同窗老是搞不清楚,内存泄漏和内存溢出的区别,它俩是两个彻底不一样的概念, 它们之间存在一些关联。
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory;
内存泄露 memory leak,是指程序在申请内存后,没法释放已申请的内存空间,一次内存泄露危害能够忽略,但内存泄露堆积后果很严重,不管多少内存,早晚会被占光。
因此内存泄漏可能会致使内存溢出,但内存溢出并不彻底都是由于内存泄漏,也有可能使用了太多的大对象致使。
最后一个重要的问题,就是如何检测 Java 的内存泄漏。目前,咱们一般使用一些工具来检查 Java 程序的内存泄漏问题。
市场上已有几种专业检查 Java 内存泄漏的工具,它们的基本工做原理大同小异,都是经过监测 Java 程序运行时,全部对象的申请、释放等动做,将内存管理的全部信息进行统计、分析、可视化。开发人员将根据这些信息判断程序是否有内存泄漏问题。
这些工具包括 Plumbr 、Eclipse Memory Analyzer、JProbe Profiler、JVisualVM 等。
以上内容实际上是我曾经常常面试的内容之一,经过一系列的问题考察 Java 程序员对 Jvm 的理解。
好比我一般会问面试者,Java 中存在内存泄漏吗?大部分人都会回答存在,接着我会问若是让你写一个程序让内存泄漏,你会怎么写?大部分程序员就回答不上来了。
若是面试者能够回答上面的问题,我会接着和面试者聊聊,内存泄漏和内存溢出他们之间是否存在联系 、以及在平常工做中如何避免写出内存泄漏的代码 、若是生产出现 Jvm 相关问题时,排查问题的思路和步骤等等。
这些问题在个人博客中都有答案,早些年写了一系列关于 Jvm 的文章,你们若是感兴趣的话接下来继续去阅读,www.ityouknow.com/java.html。
若是你们以为在手机上看着更方便,能够关注:Java 极客技术公号,已经输出了一些 JVM 文章,我博客中的 Jvm 系列文章也都会推送到这个公号中。
关注一下又不会怀孕
参考出处: