Java程序员从笨鸟到菜鸟(三十三)JVM运行原理解析

面试题

GC(Garbage Collection)垃圾回收器

收集并删除未引用的对象,可以通过调用“System.gc()”来触发垃圾回收,但并不保证会进行垃圾回收。JVM的垃圾回收只收集那些由new关键字创建的对象,如果不是new创建的对象,可以使用finalize函数来实行处理

主要形式:手工、自动
自动会不定期进行回收,以释放无用的空间
手工调用System类中的gc()方法,此方法实际上调用的是Runtime类中的gc()方法,当一个对象被回收之前将调用类中的finlalize()方法,此方法为 Object类所提供,表示对象回收前的收尾工作

垃圾回收器技术:

引用计数简单但是很慢:每个对象都有一个引用计数器,当有引用对象连接时,计数器+1,引用离开时,引用计数-1,垃圾回收器会在含有所有对象的表上遍历,当发现某个对象的引用计数为0时,释放空间,缺陷:对象之间存在循环引用,可能会出现“对象应该被回收,但引用计数却不为0的情况”,定位这些交互自引用的对象组所需的工作量很大,这种方法一般只是阐述原理,不运用

在一些更快的模式中,依据的思想:对任何“活的对象”,一定能追溯到其存活在堆栈或静态存储区的引用,这个引用链条可能会穿过数个对象层次,由此从堆栈和静态存储区开始,遍历所有的引用,就能够找到所有“活”的对象,这样就解决了“交互自引用的数组”。

如何找到存活对象:
停止-复制:先暂停程序运行,然后将所有存活的对象从当前堆复制到另一个堆,没有被复制的全是垃圾,这种所谓的“复制式回收器”效率会降低,在两个堆之间来回倒腾,需要维护多一倍的空间

标记-清扫:从堆栈存和静态存储区出发,遍历所有的引用,进而找出所有的存活对象,每当找到一个存活对象,就会给对象设一个标记,这个过程不会回收任何对象,只有全部标记完成之后,才会开始清扫,没有被标记的对象,不会发生任何复制动作

:内存分配单位,垃圾回收的时候就可以往废弃的块里拷贝对象。每个块都有相应的代数,记录是否还存活,如果块在某处被引用,代数会增加,垃圾回收器会对上次回收动作之后新分配的块进行整理

自适应垃圾回收技术:java虚拟机会进行监视,如果所有对象都很稳定,垃圾回收器的效率降低的话,就会切换到标记-清扫方式,同样,java虚拟机会跟踪标记-清扫的效果,要是堆空间中出现很多碎片,就会切换回停止-复制,这就是自适应技术

垃圾收集算法

标记-清除算法(Mark-Sweep)

标记清除,首先标记所有需要回收的对象,在标记完后统一回收所有被标记的对象,最基础的收集算法;不足效率问题,标记和清除都效率不高,空间问题标记清除后会产生大量不连续的空间碎片,碎片太多会导致程序在运行过程中需要分配较大的对象,无法找到足够连续内存,而不得不提前触发一次垃圾回收操作

复制算法(Coping)

可用内存按容量分为大小相等的两块,每次只是用其中一块,这一块内存用完了,就将存活的对象复制到另一块上面,然后再把使用过的内存空间清理掉,这样每次都是对整个半区进行回收,不用考虑内存碎片等复杂情况实现简单,运行高效,但是可用内存只有一半,代价太大。一般用于回收新生代,因为新生代对象98%都会很快被回收,所以不用1:1划分,而是分为一块较大的Eden空间和2块较小的Survior空间,默认分配大小是8:1:1,每次使用Eden和一块Survior,当回收时,将存活对象复制到另外一块Survior上,这样只有10%被浪费。复制收集算法在对对象存活率较高时就要进行较多的复制操作,效率将会降低,在老年代一般不能直接选用这种算法

标记-整理算法(Mark-Compact)

标记过程中仍然和标记-清除算法一样,但是后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后清理掉端边界以外的内存,这样就不会出现大量的空间碎片,适用于老年代

分代收集算法(Generational Collection)

当前商业虚拟机的垃圾收集器都采用分代收集算法,只是根据存活周期不同将内存分为几块。一般是把java堆分成新生代老年代,这样根据各个年代的特点采用最适当的收集算法,在新生代中,每次垃圾收集都发现有大量的对象死去,只有少量存活就用复制算法,只需要付出少量的代价就能完成垃圾回收;而老年代中因为对象存活率较高、没有额外空间进行分配担保,就必须使用标记-清理或者标记-整理算法来进行回收

JVM内存运行时数据区

这里写图片描述

java是否存在内存泄露

内存泄露:指一个不再被程序使用的对象或变量一直被占据在内存中。Java 使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达(有向图两个顶点不连通)的,那么GC也是可以回收

内存泄露的场景
1.程序员创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,这个对象无用但是无法被垃圾回收器回收
2.一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类被长期引用了,即使那个外部类实例不再被使用,由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收

猜你喜欢

转载自blog.csdn.net/u013090299/article/details/80664150
今日推荐