java是不会出现内存泄露的,你可以在new完对象之后将其进行显性的释放,调用finalize(),尽管new对象没事的,反正都可以回收掉,这是我们经常听到的,前几天听我以同学说,课本上竟然写着java内存不会发生泄露,今天就想到来写一篇关于java内存回收方面的博客。
首先这些问题的缘由就是java给广大程序员的一个许诺,我有垃圾回收机制,有了垃圾回收机制就一定不会内存泄露??
先从内存泄露这个概念来说吧,在程序的运行期间会不断的分配内存,当非配的内存空间不再被使用的时候但是没有被回收回来这就是内存泄露。
对象在内存中的状态,有三种状态,1.可到达状态,2.可恢复状态3.不可到达状态。
JVM的垃圾回收机制采用的是有向图的方式来进行管理内存中的对象,可以比较方便的解决一些比较复杂的引用问题,也是根据有向图的机制来进行,
通过上面的图我们可以看出,三个引用P1,P2,P3的指向分别为Kevin,无指向,Rain,其中Kevin有一个路径指向,Rain有两个路径指向,但是sunny没有引用指向它,失去了引用,所以sunny是不可达状态就会被垃圾回收机制回收,其中,当其丧失引用之后并不是立即成为了不可达状态而是首先作为可恢复状态,系统会调用finalize()进行资源清理,如果该方法使得该对象出现了一个以上的引用,那么其再次成为了可到达状态。垃圾回收机制判断一个对象是否可回收的标准就是该对象现在是否还被引用。
对象的引用类型
对象为引用类型有四种,分别为强引用,弱引用,软引用,虚引用。不同的引用对对象的生命周期有着很大的影响,首先是强引用,也是我们使用最多的引用方式也就是创建一个对象,并把这个对象赋给一个引用,被强引用的java对象永远不会被回收,虽然有一些我们已经是不再使用了,但是它还是存在内存之中的,所以强类型成了导致java内存泄露的主要原因,其它三种引用可能是我们再做一些小型的开发过程中很少用到的,对于这三类来说无非就是声明周期比强引用的要短,软引用,通过SoftReference类来进行实现,当内存空间足够的时候,它和强类型是没有什么区别的,是不会被回收的,但是当空间不足的时候就会被回收掉,但是强类型是不会被回收的,这就会导致整个程序crash,所以我们在需要new出很多对象的地方使用软引用,来防止程序崩溃,来提升用户体验,但是不足的地方就是其中的对象是否已经被释放掉了我们是不知道的,这就会导致出现空指针引用,但是我们在后面添加一个判断语句来进行判断是否为null。
下面展现一个软引用的代码实例
class Person{
String name;
public Person(String name){
this.name = name;
}
}
public class Test (){
public static void main(String []args){
SoftReference<Person>[]people = new SoftReference[100000];
for (int i = 0;i <people.length;i++){
people[i]= new SoftReference<Person>(new Person("snowsea"));
}
System.out.println(people[2].get());
}
}
我们得到的输出值是null,但是如果是用强类型的话我们得到的就是整个程序crash了。对于弱引用就是采用弱引用的就和失去引用的一样处在可恢复状态,在垃圾机制回收的时候就会被立即回收。
内存泄露,在这方面java做的不得不说确实要比其他语言好,拿C++来说,对于其中的丧失引用的对象,我们要自己显示的调用代码进行回收,通过下面这个图看一下
c++中的对象一旦未正确释放,丧失了引用之后就会导致该对象处于一个不可达的状态,这就会使得我们无法找到,想释放也无能为力,通过代码,我们可以将该对象存在的空间交给系统也就将其释放掉,但是java的垃圾回收机制使得每一个对象都处在一个被监控的状态,JVM可以回收这个方框中的任何对象。
自己之前涉及到一点关于垃圾回收机制设计的算法问题,大致有以下的几种方式,从以下几个角度来进行分析,1.cpu,串行回收,也就只有一个cpu来执行这个操作,第二就是并行回收,就是有多个cpu同时运作进行垃圾回收,第一中方式效率肯定要比第二种方式要低一些,但是第二种方式就会出现内存碎片的问题,应为回收的过程是由多个cpu来进行处理的,主要并行回收,也并不是说这几个cpu同时进行,而是多个cpu间歇性的运作,也就是这个执行一段时间,另一个接着去执行,在设计上的复杂度比较大,而且会出现内存碎片,内存碎片有两种一种是内部碎片,另一种是外部碎片,外部碎片是未被分配给确定的对象,但是却无法使用的,由于空间比较小,内部碎片就是在已分配的空间中存在的程序不可利用的空间,并行就容易产生外部碎片。
2执行方式 并发执行和应用程序停止执行,并发执行容易和当前正在运行的程序产生冲突,设计难度比较大,应用程序停止对用户的体验可能不够好,在设计上要比并发简单很多。3.回收方式 压缩,不压缩,和复制 压缩就是先将当前可到达的对象搬迁在一起,然后释放掉不可到达的,不压缩就是对其内存空间进行遍历,然后释放掉不可到达到的,这中方式的缺陷就是容易产生外部内存碎片,复制就是将可到达的复制出一份,然后将原来的释放掉,缺陷就是比较吃内存。