深入理解JVM

JVM

类加载的过程
类加载器

双亲委派模式是在Java 1.2后引入的,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载。

双亲委派模式好处
1.可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次
2.防止核心API库被随意篡改,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class

什么是垃圾回收

垃圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制。

垃圾回收的过程

  1. 当对象创建后会被分配到Eden区。
  2. Eden区空间被填满时,会触发轻微的垃圾收集Minor GC。引用的对象被移动到第一个幸存区S0;清除Eden区时,将删除未引用的对象。
  3. 当再次放生Minor GC时,就会对Eden和S0一起进行垃圾回收,将存活的对象复制到S1,然后清空Eden和S0
  4. 年轻代垃圾回收就是上面的三步,不断地复制清除。
  5. 在年轻代中进行垃圾回收存活的对象有一个岁数,垃圾回收一次就会加一,默认值是15,当到达临界年龄,对象就会被复制到老年代;当老年代的被占满,无法再进入对象时,就会进行一次Full GC,这个垃圾回收的时间比较长

Object的Finalize
finalize()方法是Object类的一个protected方法,所以所有的类都可以调用Object类的finalize()方法,也可以自己去重写finalize()方法。

finalize的执行过程
当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程(不保证一定会执行,可能在没有遍历完之前,就已经被剥夺了运行的权利)执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,这个对象将从F-Queue中移除。
Object finalize()方法是在垃圾收集器回收对象之前会调用这个方法。

垃圾回收机制中的6种算法

1.引用计数法(Reference Counting Collector)
给对象中添加一个引用计数器,每个对象有15次机会,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器都为0的对象就是不再被使用的,垃圾收集器将回收该对象使用的内存。
优点:引用计数收集器可以很快的执行,交织在程序运行中。
缺点:无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。

2.根搜索算法
这个算法的基本思路就是通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。

3.复制算法 复制算法用于在新生代垃圾回收
From Survivor空间S0和 To Survivor空间s1将可用内存按容量分成大小相等的两块,每次只使用其中一块,当这块内存使用完了,就将还存活的对象复制到另一块内存上去,然后把使用过的内存空间一次清理掉。这样使得每次都是对其中一块内存进行回收,内存分配时不用考虑内存碎片等复杂情况,只需要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
复制算法的缺点显而易见,可使用的内存降为原来一半。

4.标记-清除算法分析
标记-清除算法采用从根集合进行扫描,对存活的对象对象标记,标记完毕后,再扫描整个空间中未被标记的对象,进行回收,如上图所示。标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但由于标记-清除算法直接回收不存活的对象,因此会造成内存碎片。

5.标记-整理算法compacting
采用标记-清除算法一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存碎片的问题。

6.generation算法(Generational Collector)分区算法
根据内存中对象的存活周期不同,将内存划分为几块,java的虚拟机中一般把内存划分为新生代和年老代,当新创建对象时一般在新生代中分配内存空间,当新生代垃圾收集器回收几次之后仍然存活的对象会被移动到年老代内存中,当大对象在新生代中无法找到足够的连续内存时也直接在年老代中创建。

垃圾收集器 7种
收集器特点
Serial收集器单线程、复制算法、新生代
ParNew 收集器多线程、复制算法、新生代
Parallel Scavenge 收集器多线程、复制算法、自适应调节策略、新生代
Serial Old收集器单线程、标记整理、老年代
Parallel Old收集器多线程、标记整理、老年代
CMS(Concurrent Mark Sweep)并发收集、低停顿、标记清除、老年代
G1(Garbage-First)横跨整个堆内存、标记整理
  • CMS等收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标是达到一个可控制的吞吐量(Throughput)。
  • G1(Garbage-First)当今收集器技术发展最前沿的成果之一,它是一款面向服务端应用的垃圾收集器,HotSpot开发团队赋予它的使命是(在比较长期的)未来可以替换掉JDK 1.5中发布的CMS收集器。
    G1从整体来看是基于“标记-整理”算法实现的收集器。横跨整个堆内存,在G1之前的其他收集器进行收集的范围都是整个新生代或者老生代,而G1不再是这样。G1在使用时,Java堆的内存布局与其他收集器有很大区别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,而都是一部分Region(不需要连续)的集合;在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage-First名称的来由)
JVM 优化经验总结
  1. 设置稳定的堆大小对垃圾回收是有利的;减少GC的回收,原因频繁的GC回收会对系统有一定的影响,应用程序会短暂的停顿;-Xms 初始堆大小 和 -Xmx 最大堆大小 设置成一样
  2. 将新对象预留在年轻代;由于 Full GC 的成本远远高于 Minor GC。一般来说,Survivor 区的空间不够,或者占用量达到 50%时,就会使对象进入年老代 (不管它的年龄有多大)。尝试加上-XX:TargetSurvivorRatio=90 参数,这样可以提高 from 区的利用率,使 from 区使用到 90%时,再将对象送入年老代
  3. 增大吞吐量提升系统性能。在拥有高性能的计算机上,进行吞吐量优先优化,故可以考虑关注系统吞吐量的并行回收收集器。
    可以使用参数:java –Xmx3800m –Xms3800m –Xmn2G –Xss128k –XX:+UseParallelGC –XX:ParallelGC-Threads=20 –XX:+UseParallelOldGC
    -Xss128k:减少线程栈的大小,这样可以使剩余的系统内存支持更多的线程;
    -Xmn2g:设置年轻代区域大小为 2GB;
    –XX:+UseParallelGC:年轻代使用并行垃圾回收收集器。这是一个关注吞吐量的收集器,可以尽可能地减少 GC 时间。
    –XX:ParallelGC-Threads:设置用于垃圾回收的线程数,通常情况下,可以设置和 CPU 数量相等。但在 CPU 数量比较多的情况下,设置相对较小的数值也是合理的;
    –XX:+UseParallelOldGC:设置年老代使用并行回收收集器。
  4. 降低应用软件的垃圾回收时的停顿,首先考虑的是使用关注系统停顿的 CMS 回收器,其次,为了减少 Full GC 次数,应尽可能将对象预留在年轻代,因为年轻代 Minor GC 的成本远远小于年老代的 Full GC。
    可以使用参数:java –Xmx3550m –Xms3550m –Xmn2g –Xss128k –XX:ParallelGCThreads=20 –XX:+UseConcMarkSweepGC –XX:+UseParNewGC –XX:+SurvivorRatio=8 –XX:TargetSurvivorRatio=90 –XX:MaxTenuringThreshold=31
    –XX:ParallelGCThreads=20:设置 20 个线程进行垃圾回收;
    –XX:+UseParNewGC:年轻代使用并行回收器;
    –XX:+UseConcMarkSweepGC:年老代使用 CMS 收集器降低停顿;
    –XX:+SurvivorRatio:设置 Eden 区和 Survivor 区的比例为 8:1。稍大的 Survivor 空间可以提高在年轻代回收生命周期较短的对象的可能性,如果 Survivor 不够大,一些短命的对象可能直接进入年老代,这对系统来说是不利的。
    –XX:TargetSurvivorRatio=90:设置 Survivor 区的可使用率。这里设置为 90%,则允许 90%的 Survivor 空间被使用。默认值是 50%。故该设置提高了 Survivor 区的使用率。当存放的对象超过这个百分比,则对象会向年老代压缩。因此,这个选项更有助于将对象留在年轻代。
    –XX:MaxTenuringThreshold:设置年轻对象晋升到年老代的年龄。默认值是 15 次,即对象经过 15 次 Minor GC 依然存活,则进入年老代。这里设置为 31,目的是让对象尽可能地保存在年轻代区域。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值