回复“000”获取大量电子书 在 其实就是这三个的生命周期和线程的生命周期一样。都是每个线程私有的。 每次方法的调用就会向栈里入栈一个栈帧,方法调用结束,跟着就出栈。 对象也是有生命周期的,所以对于不需要的对象要进行必要的清楚,否则久而久之,我们的内存就被一点一点的消耗完。 今天来学习,如何判断对象是否已经可以被回收?以及回收有哪些算法? 如何判断对象已死?引用计数法给对象添加一个引用计数器,每当一个地方引用它object时技术加1,引用失去以后就减1,计数为0说明不再引用。
public class A { 可达性分析算法当一个对象到
public class Test{ 对象的引用类型强引用: User user=new User(); 我们开发中使用最多的对象引用方式。 特点:我们平常典型编码Object obj = new Object()中的obj就是强引用。 通过关键字new创建的对象所关联的引用就是强引用。 当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。 对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略。 软引用: SoftReference object=new SoftReference(new Object()); 特点:软引用通过SoftReference类实现。软引用的生命周期比强引用短一些。 只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象:即JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。 后续,我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。 应用场景:软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。 弱引用: WeakReference object=new WeakReference (new Object(); ThreadLocal中有使用。 弱引用通过WeakReference类实现。弱引用的生命周期比软引用短。 在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。应用场景:弱应用同样可用于内存敏感的缓存。 虚引用: 几乎没见过使用, ReferenceQueue 、PhantomReference。 finalize方法这个方法就有点类似于“某个人被判了死刑,但是不一定会死”的情景。 即使在可达性分析算法中不可达的对象,也并非一定是“非死不可”的,这时候他们暂时处于“缓刑”阶段,真正宣告一个对象死亡至少要经历两个阶段: 1、如果对象在可达性分析算法中不可达,那么它会被第一次标记并进行一次刷选,刷选的条件是是否需要执行finalize()方法(当对象没有覆盖finalize()或者finalize()方法已经执行过了(对象的此方法只会执行一次)),虚拟机将这两种情况都会视为没有必要执行)。 2、如果这个对象有必要执行finalize()方法会将其放入F-Queue队列中,稍后GC将对F-Queue队列进行第二次标记,如果在重写finalize()方法中将对象自己赋值给某个类变量或者对象的成员变量,那么第二次标记时候就会将它移出“即将回收”的集合。 方法区的回收在堆中,尤其是在新生代中,一次垃圾回收一般可以回收 70% ~ 95% 的空间,而方法区的垃圾收集效率远低于此。 方法区垃圾回收主要两部分内容:废弃的常量和无用的类。 标记-清除第一步:就是找出活跃的对象。我们反复强调 GC 过程是逆向的, 根据 GC Roots 遍历所有的可达对象,这个过程,就叫作标记。 第二步:除了上面标记出来的对象以外,其余的都清除掉。
复制新生代使用,新生代分中 当其中一块内存使用完了,就将还存活的对象复制到另外一块上面,然后把已经使用过的内存空间一次清除掉。 一般对象分配都是进入新生代的eden区,如果
标记整理它的主要思路,就是移动所有存活的对象,且按照内存地址顺序依次排列,然后将末端内存地址以后的内存全部回收。 但是需要注意,这只是一个理想状态。对象的引用关系一般都是非常复杂的,我们这里不对具体的算法进行描述。我们只需要了解,从效率上来说,一般整理算法是要低于复制算法的。这个算法是规避了内存碎片和内存浪费。 让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。 从上面的三个算法来看,其实没有绝对最好的回收算法,只有最适合的算法。 STW
在JVM中也有这么个说法,就是STW,是指JVM垃圾收集器在收集垃圾对象的时候,其他所有线程都被挂起(除了垃圾收集器之外),JVM中一种全局暂停现象。 ----全局停顿,想想就很可怕,所有的Java代码停止执行,native代码可以执行,但是不能与JVM进行交互,这些基本上都是由于GC引起的。 但是也还有另外的几种场景也可以导致STW: 1.Garbage collection pauses |
|