常见的垃圾回收机制不包括(常见的垃圾回收机制)
如何工作
在某些 Java 虚拟机中 ,堆的实现截然不同:它更像一个传送带 ,每分配一个新对象 ,它就向前移动一格 。
这意味着对象存储空间的分配速度特别快 。Java 的"堆指针"只是简单地移动到尚未分配的区域 ,所以它的效率与 C++ 在栈上分配空间的效率相当
垃圾回收器工作时 ,一边回收内存 ,一边使堆中的对象紧凑排列 ,这样堆指针就可以更容易的移动到空闲区域的位置上
垃圾收集器在分配存储空间的同时会将对象重新排列 ,由此实现一个高速的 、有无限空闲空间的堆模型。
对象可能不被垃圾回收 垃圾回收不等于析构 垃圾回收只与内存有关 无论是“垃圾回收 ”还是“终结 ” ,都不一定保证会发生; 如果java虚拟机(JVM)并未面临内存耗尽的情况,它可能不会浪费时间执行垃圾回收以恢复内存finalize()方法 (有个大概印象即可)
finalize()方法需要使用finalize()的特殊情况:你创建的对象不是通过new来分配内存的 ,而垃圾回收器只知道如何释放用new创建的对象内存 。java允许在类中定义一个名为finalize()的方法(继承与Object)来处理这种情况
finalize()方法 的使用案例
释放 通过某种创建对象方式之外的方式 为对象分配的存储空间
解释:上边的情况 主要发生在使用本地方法的情况下 ,本地方法主要支持C/C++,这也许会调用C的malloc()函数来分配空间 ,这时 ,如果没用调用free()方法主动释放malloc到的空间,就会造成内存泄漏 ,所以需要在finalize()方法中调用free
终结条件
安全的标记对象是否可以被终结 ,例如下例 要销毁未被登记的Book对象时 ,报错
class Book{ boolean checkedOut = false; public Book(boolean checkOut) { this.checkedOut = checkOut; } void checkIn(){ this.checkedOut = false; } @Override protected void finalize()throws Throwable{ //只有登记过的 才能被删除 这就可以作为终结的条件 if(checkedOut){ System.out.println("ERROR: checked out"); } // Normally, youll also do this: // super.finalize(); // Call the base-class version } } public class JavaTest{ @Test public void test8() throws InterruptedException { Book book = new Book(true); book.checkIn(); new Book(true); System.gc(); Thread.sleep(1000); } }垃圾回收机制
引用计数原理:每个对象中都有一个引用计数器 ,每当有引用指向该对象时 ,引用计数器+1;当引用离开作用域或是被置为null时 ,引用计数器-1;如果发现某个对象的引用计数为0时 ,就释放其空间(引用计数器模式经常会在计数器为0时立即释放对象)
特点:
简单
速度慢(开销不大 ,但在整个生命周期频繁发生的负担)
在每次内存对象被引用或引用被销毁的时候都必须修改引用计数 ,这类操作被称为footprint 。引用计数的footprint是很高的 。这使得程序整体的性能受到比较大的影响
出现循环引用时会出问题(应该被回收,但没有)
.btw:"引用计数通常用于解释垃圾收集的工作方式 ,但它似乎并没有出现在任何JVM实现中"
更快的策略依据对于任何没有被废弃的对象 ,最终都能追溯到它存活在栈或静态存储区中的引用
因此,如果从栈和静态存储区开始遍历所有引用(包括对象内部的) ,就能找到所有存活的对象
匿名对象的相关思考:我们通常将匿名对象作为方法参数传递 ,func(new B()),在该方法中 ,B对象被关联了引用
所以 ,遍历所有的引用即可得到所有“活 ”的对象 ,然后再去遍历这些对象中的引用 ,如此反复 ,就能得到一个对象网络 ,其中的对象就都是 活 的;
循环引用示例 class A{ public B b; } class B{ public A a; } public class Main{ public static void main(String[] args){ A a = new A(); // A对象被引用 A对象计数器+1 B b = new B(); // B对象被引用 B对象计数器+1 a.b=b; // B对象被引用 B对象计数器+1 b.a=a; // A对象被引用 A对象计数器+1 } }上例 当栈上的引用遍历到a ,发现a对象中有个B对象的引用 ,指向b ,这个b引用中又有个A的引用 又指向a 如此循环 根本找不到活的对象
这样也解决了循环引用问题,循环引用的对象不会被发现
停止-复制(stop-and-copy)原理:先暂停程序的运行 ,然后将所有存活的对象从当前堆复制到另一个堆 ,没有被复制的就是需要垃圾回收的,而且 ,当对象被复制到新堆后 ,他们紧凑排列的,一个挨着一个
特点:
解决了循环引用的问题(循环引用的对象不会被发现) 非后台回收模式(需要在程序暂停的情况下进行) 相对较快 效率低下得有两个堆:还得在这两个分离的堆之间来回折腾 ,得维护比实际多一倍的空间
某些jvm的解决方式:按需在堆中分配几块较大的内存 ,复制动作就发生在这大内存间复制本身:一旦程序进入稳定状态 ,可能只会产生少量垃圾 ,甚至没有 ,就算是这 ,复制回收器也得将所有 内存从一处复制到另一处 ,太浪费了
某些JVM的解决方式:进行检查 ,要是没有新的垃圾产生 ,就会转换到“标记-清扫"模式(SUN公司早期JVM一直在用) 。对一般用途,这种方法很慢 ,但当程序只会产生少量或者不产生垃圾 ,他速度就很快了 切换到标记清扫方式清理 标记-清扫原理:标记:从栈和静态存储区出发,遍历所有引用 ,找出所有“活 ”对象 ,每找到一个,就给对象一个标记 ,直到遍历完所有对象;清扫:没有被标记的对象将被清理 。
特点:
解决了循环引用的问题(循环引用的对象不会被发现) 相比停止-复制 较为高效(不会有任何复制动作) 非后台回收模式(需要在程序暂停的情况下进行) 处理完后剩下的堆空间是不连续的 垃圾回收器若希望得到连续的空间 ,就需要整理剩下的未被清理的对象 补充:标记-整理原理:标记:从栈和静态区域出发 ,遍历所有引用 ,对遍历过程中得到的活的对象进行标记;整理:将标记过的对象 ,把他们从内存开始的地方按照顺序依次摆放好 ,中间没有任何缝隙 ,在摆放完最后一个对象后 ,对后面的内存区域直接回收 。
JVM中的块(感觉像是年龄分代) 内存分配以较大的"块"为单位 ,较大的对象会单独占一个块 。 块用年代数来记录自己是否存活,若块被引用 ,年代数+1 。 垃圾回收器会对上一次回收过后 新分配的块进行整理 垃圾回收器定期会清理 含有小对象的那些块将被复制 、整理 大型对象 不会被复制(只有年代数会增加) 补充:分代收集算法摘自JavaGuide
当前虚拟机的垃圾收集都采用分代收集算法 ,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块 。一般将 java 堆分为新生代和老年代 ,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
比如在新生代中 ,每次收集都会有大量对象死去,所以可以选择 ”标记-复制“算法 ,只需要付出少量对象的复制成本就可以完成每次垃圾收集 。而老年代的对象存活几率是比较高的 ,而且没有额外的空间对它进行分配担保 ,所以我们必须选择“标记-清除 ”或“标记-整理 ”算法进行垃圾收集 。
标记清扫与停止复制的切换机制(自适应)如果对象一个个的都很稳定 ,此时如果垃圾回收效率降低了 ,就会切换到“标记-清扫 ”模式 ,以提高垃圾回收的效率 ,(此时jvm持续监视) 如果堆中的碎片多了 ,那么就赶紧切换回“停止-复制 ”模式 ,以真整理堆空间,保持堆的高速运转。
HotSpot技术 java执行步骤 即时编译技术(Just-in Time JIT)想要了解更多请移步什么是JIT?怎么优化? - 知乎 (zhihu.com)
热点代码分为两类:
多次调用的方法 多次执行的循环体 ,实际上也会以整个方法作为编译对象如何判断热点代码请看原文
可以把 全部或部分 程序 直接翻译为本地机器码 ,这就省去了JVM翻译,所以运行更快
为什么不能用这个技术 编译所有代码?
这个技术贯穿整个程序的生命周期 ,累加起来慢的要死 会增加可执行代码的长度(字节码要比即时编译器展开后的本地机器码小很多) ,导致页面调度,使程序运行变慢 即时编译时以方法为单位的 ,如果编译出来的代码运行不了几次 ,就白编译了 惰性评估即时编译器只有在必要时 ,才编译代码
这样 ,从未被执行的代码也许就压根不会被 JIT 编译 。
新版 JDK 中的 Java HotSpot 技术就采用了类似的做法 ,代码每被执行一次就优化一些 ,所以执行的次数越多 ,它的速度就越快 。
逃逸分析技术请移步至深入理解Java中的逃逸分析
逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后 ,它可能被外部方法所引用 ,例如作为调用参数传递到其他地方中,称为方法逃逸。
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!