济南网站建设网站,wordpress 回复 验证码,小红书seo排名帝搜软件,济源网站建设哪家好一、为什么会有年轻代
我们先来屡屡#xff0c;为什么需要把堆分代#xff1f;不分代不能完成他所做的事情么#xff1f;其实不分代完全可以#xff0c;分代的唯一理由就是优化GC性能。你先想想#xff0c;如果没有分代#xff0c;那我们所有的对象都在一块#xff0c;…一、为什么会有年轻代
我们先来屡屡为什么需要把堆分代不分代不能完成他所做的事情么其实不分代完全可以分代的唯一理由就是优化GC性能。你先想想如果没有分代那我们所有的对象都在一块GC的时候我们要找到哪些对象没用这样就会对堆的所有区域进行扫描。而我们的很多对象都是朝生夕死的如果分代的话我们把新创建的对象放到某一地方当GC的时候先把这块存“朝生夕死”对象的区域进行回收这样就会腾出很大的空间出来。
二.年轻代中的GC
新生代大小PSYoungGen total 9216Keden大小eden space 8192K1个survivor大小from space 1024K
HotSpot JVM把年轻代分为了三部分1个Eden区和2个Survivor区分别叫from和to。默认比例为8Eden1一个survivor,为啥默认会是这个比例接下来我们会聊到。一般情况下新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后如果仍然存活将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC年龄就会增加1岁当它的年龄增加到一定程度时就会被移动到年老代中。 因为年轻代中的对象基本都是朝生夕死的(80%以上)所以在年轻代的垃圾回收算法使用的是复制算法复制算法的基本思想就是将内存分为两块每次只用其中一块当这一块内存用完就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。 在GC开始的时候对象只会存在于Eden区和名为“From”的Survivor区Survivor区“To”是空的。紧接着进行GCEden区中所有存活的对象都会被复制到“To”而在“From”区中仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中没有达到阈值的对象会被复制到“To”区域。经过这次GC后Eden区和From区已经被清空。这个时候“From”和“To”会交换他们的角色也就是新的“To”就是上次GC前的“From”新的“From”就是上次GC前的“To”。不管怎样都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程直到“To”区被填满“To”区被填满之后会将所有对象移动到年老代中。
三、一个对象的这一辈子
我是一个普通的Java对象我出生在Eden区在Eden区我还看到和我长的很像的小兄弟我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了我就被迫去了Survivor区的“From”区自从去了Survivor区我就开始漂了有时候在Survivor的“From”区有时候在Survivor的“To”区居无定所。直到我18岁的时候爸爸说我成人了该去社会上闯闯了。于是我就去了年老代那边年老代里人很多并且年龄都挺大的我在这里也认识了很多人。在年老代里我生活了20年(每次GC加一岁)然后被回收。
四、为什么要有Survivor区
先不去想为什么有两个Survivor区第一个问题是设置Survivor区的意义在哪里 如果没有SurvivorEden区每进行一次Minor GC存活的对象就会被送到老年代。老年代很快被填满触发Major GC因为Major GC一般伴随着Minor GC也可以看做触发了Full GC。老年代的内存空间远大于新生代进行一次Full GC消耗的时间比Minor GC长得多。你也许会问执行时间长有什么坏处频发的Full GC消耗的时间是非常可观的这一点会影响大型程序的执行和响应速度更不要说某些连接会因为超时发生连接错误了。
好那我们来想想在没有Survivor的情况下有没有什么解决办法可以避免上述情况 显而易见没有Survivor的话上述两种解决方案都不能从根本上解决问题。
我们可以得到第一条结论Survivor的存在意义就是减少被送到老年代的对象进而减少Full GC的发生Survivor的预筛选保证只有经历16次Minor GC还能在新生代中存活的对象才会被送到老年代。
五、为什么要设置两个Survivor区
设置两个Survivor区最大的好处就是解决了碎片化下面我们来分析一下。
为什么一个Survivor区不行第一部分中我们知道了必须设置Survivor区。假设现在只有一个survivor区我们来模拟一下流程 刚刚新建的对象在Eden中一旦Eden满了触发一次Minor GCEden中的存活对象就会被移动到Survivor区。这样继续循环下去下一次Eden满了的时候问题来了此时进行Minor GCEden和Survivor各有一些存活对象如果此时把Eden区的存活对象硬放到Survivor区很明显这两部分对象所占有的内存是不连续的也就导致了内存碎片化。 我绘制了一幅图来表明这个过程。其中色块代表对象白色框分别代表Eden区大和Survivor区小。Eden区理所当然大一些否则新建对象很快就导致Eden区满进而触发Minor GC有悖于初衷。 碎片化带来的风险是极大的严重影响Java程序的性能。堆空间被散布的对象占据不连续的内存最直接的结果就是堆中没有足够大的连续内存空间接下去如果程序需要给一个内存需求很大的对象分配内存。。。画面太美不敢看。。。这就好比我们爬山的时候背包里所有东西紧挨着放最后就可能省出一块完整的空间放相机。如果每件行李之间隔一点空隙乱放很可能最后就要一路把相机挂在脖子上了。
那么顺理成章的应该建立两块Survivor区刚刚新建的对象在Eden中经历一次Minor GCEden中的存活对象就会被移动到第一块survivor space S0Eden被清空等Eden区再满了就再触发一次Minor GCEden和S0中的存活对象又会被复制送入第二块survivor space S1这个过程非常重要因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间避免了碎片化的发生。S0和Eden被清空然后下一轮S0与S1交换角色如此循环往复。如果对象的复制次数达到16次该对象就会被送到老年代中。下图中每部分的意义和上一张图一样就不加注释了。 上述机制最大的好处就是整个过程中永远有一个survivor space是空的另一个非空的survivor space无碎片。
那么Survivor为什么不分更多块呢比方说分成三个、四个、五个?显然如果Survivor区再细分下去每一块的空间就会比较小很容易导致Survivor区满因此我认为两块Survivor区是经过权衡之后的最佳方案。
原文https://www.cnblogs.com/duanxz/p/6076662.html