搞java的都知道在编写java程序的时候不需要要考虑资源的释放,因为JVM会自动将不是用的对象GC掉。这里自动是个什么原因呢?就是程序员不能对垃圾进行回收,垃圾回收并不会及时清理内存,即便有时候程序需要需要的额外内存,垃圾回收不会随时发生。所以如果想写出高校的程序,需要根据垃圾回收的原则,合理的分配内存。
为什么要进行垃圾回收?
随着程序的运行,对象、变量占据的内存不断增多,如果不及时的回收这些内存资源,程序的性能会不断的下降,甚至会使系统出现一些问题;
哪里垃圾需要进行回收?
我们知道堆是用来存放对象的地方,这个地方是垃圾回收的重要地方,还有就是方法区,方法区中有着许多变量。为什么JVM栈、本地方法栈、PC计数器不用垃圾回收?因为这些的生命周期是与线程同步的,随着线程的销毁这些内存也会自动释放。
什么时候进行垃圾回收?
有一种算法是计数器算法,为每个对象添加一个计数器,当引用一次计数器加1,失去引用计数器减1。当计数器为0的时候则可以进行回收了。但是这种算法有明显的错误,如当两个对象互相引用但是却都没有用的时候,他们已经没有用了,但是又不符合垃圾回收的规则,所以JVM并没有使用这种策略。而是采用一种根搜索的算法。
他的基本思想就是:从一个叫做GC Roots的对象开始向下进行搜索,如果一个对象不能够到达这个GC Roots,也就是失去引用了,就可以进行回收了(考虑也有finalize()方法的对象)。如上图的o5,o6,o7即便互相引用呢,但是无法到达GC Roots对象,所以可以进行垃圾回收了。
引用是什么?
引用分为强引用、软引用、弱引用、虚引用四中。
强引用:就是刚刚创建的对象所加的引用,他不会被GC
软引用:是可被回收的,如果内存不紧张,则不会被GC,如果内存紧张则就会被回收。为什么可以被回收却不回收呢?比如内存缓冲区中,一个对象只是暂时没有被引用,下次引用的时候如果缓冲区中有这个引用则就直接使用,如果没有这个引用就会创建,所以他是可以被回收的。
弱引用:就是一定要被GC的,不管内存是否紧张,在GC的时候,只要这个对象被标记为弱引用,则就会被GC
虚引用:就是可以被忽略不计的,他的作用只是进行一些跟踪记录,辅助finalize()函数使用。
什么样的类需要被回收?
该类的所有实例都已经被回收了
加载该来的ClassLoader已经被回收了
该类对应的反射类对象没有被任何地方使用
如何进行垃圾回收?
由上面回收哪里的垃圾,可以知道垃圾回收针对的是新生代、旧生代、持久代。不同代有着不同的GC算法。对于新生代适合那些声明周期较短、频繁创建和销毁的对象;旧生代适合与声明周期较长的对象;持久代主要适合一些常量,默认信息等。
常见算法:
标记-清除算法(mark-sweep)
最基础的GC算法,就是将要回收的对象标记,之后扫描的时候对标记的对象,进行回收。这样就会需要产生标记和删除两个步骤,所以效率不高,而且还会产生碎片,如果大对象需要使用连续的内存空间,则还需要清理碎片。
复制算法(copying)
我们知道新生代有三个区域Eden和两个Survivor,JVM会将二者比例协调为8:1,在Survivor中有一块空闲的区域。当进行垃圾回收的时候将不需要GC的对象放到这块空闲区域,然后将Eden和Survivor这两个区域进行完全清理。这样可以会有一个问题,就是如果这块空闲的区域不够大,怎么办。这时候就需要借助持久代的区域了。