首先是关于新生代中的内存分布的描述:

新生代中的对象都是“朝生夕死”的对象,所以每次gc存活的对象很少,于是在新生代中采用的垃圾回收算法是“复制算法”。

将新生代的内存分为一块较大的Eden区域和两块较小的Survivor区域。每次使用Eden和其中一块Survivor空间。回收的时候,将Eden和Survivor中还存活着的对象一次性地复制到另一块空间上,最后清理Eden和刚才用过的Survivor空间。

HotPost虚拟机默认Eden和Survivor的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有百分之10%的内存会被浪费。

当Survivor空间不够放的时候,需要依赖其他内存(这里指老年代)进行分配担保。

这是书上(《深入理解Java虚拟机》)对于复制算法的描述。

但在后面更详细地讲内存分配与回收策略的时候:

书上说:在大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机发起一次Minor GC。

这就有点疑惑了,照这么说超过Eden就执行mimor gc,然后survivor只是用来放存活的对象的,那为什么要两个呢?

这是为了解决内存碎片化的问题。

假设我们现在只有一个Survivor空间。

刚刚新建的对象在Eden中,一旦Eden满了,触发一次Minor GC,Eden中的存活对象就会被移动到Survivor区。下一次Eden满了的时候,问题来了,此时进行Minor GC,Eden和Survivor各有一些存活对象,因为只有一个Survivor,所以Eden第二次的gc发现的存活对象也是放在唯一的一个Survivor区域中。但此时把Eden区的存活对象硬放到Survivor区,很明显这两部分对象所占有的内存是不连续的,也就导致了内存碎片化。

看图来理解:

(图片来自:https://blog.csdn.net/antony9118/article/details/51425581)

第一个图,是Eden中蓝色的内存装满了,要gc,然后Survivor区中的黄色内存,是上一次gc从Eden过来的存活对象。

第二个图是触发gc后,通过可达性判断,把活着的对象找出来。蓝色的Eden中剩一小丢存活对象,注意Survivor区中的对象也会死掉!所以现在Survivor区的对象也不是从头充满Survivor区域的了。

然后第三个图便是把Eden存活的对象放到Survivor中去,这时就产生了碎片化。

那么要怎么解决这个问题呢?

  1. 试图将Eden区存活的对象转移到survivor中,努力适应这种不连续的空间。但是不连续的空间会导致再分配大对象的时候,由于没有连续的空间来分配,会导致提前垃圾回收。
  2. 将survivor中的所有存活对象向下移动来消除碎片,然后将所有的存活对象移入其中。这样做会降低效率。
  3. 把两个区域中的所有存活对象都转移到完全独立的空间中,也就是第二块Survivor中,这样就可以留出一块完全空着的Eden和Survivor了,下次GC的时候再重复这个流程

显然方案三好点hh,所以我们便要有两个Survivor区。

那么,顺理成章的,应该建立两块Survivor区。

刚刚新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生)。S0和Eden被清空,然后下一轮S0与S1交换角色,如此循环往复。

看图:

(图片来自:https://blog.csdn.net/antony9118/article/details/51425581)

上述机制最大的好处就是,整个过程中,永远有一个survivor space是空的,另一个非空的survivor space无碎片。

参考文章:

https://blog.csdn.net/antony9118/article/details/51425581

https://www.jianshu.com/p/a5fd5bf93d26

新生代内存中为什么要有两个survivor区的更多相关文章

  1. 在JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区

    在JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区? 1 为什么要有Survivor区 先不去想为什么有两个Survivor区,第一个问题是,设置Survivor区的意义在哪 ...

  2. JVM内存结构之二--新生代及新生代里的两个Survivor区(下一轮S0与S1交换角色,如此循环往复)、常见调优参数

    一.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我 ...

  3. 为什么新生代内存需要有两个Survivor区

    转载自:http://blog.csdn.net/antony9118/article/details/51425581 在JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区? ...

  4. JVM内存结构--新生代及新生代里的两个Survivor区(下一轮S0与S1交换角色,如此循环往复)、常见调优参数

    一.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我 ...

  5. 为什么新生代内存需要有两个Survivor区?

    对于常见的GC算法,我们都应该知道,例如:标记清除算法.复制算法.标记整理算法等.标记清除算法由于回收之后存在大量的内存碎片,存在效率和空间问题!为了解决效率问题,引出了复制算法!熟悉GC算法的小伙伴 ...

  6. JVM体系结构之六:堆Heap之2:新生代及新生代里的两个Survivor区(下一轮S0与S1交换角色,如此循环往复)、常见调优参数

    一.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我 ...

  7. 新生代Eden与两个Survivor区的解释

    文章出处:http://ifeve.com/jvm-yong-generation/ 聊聊JVM的年轻代 1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分 ...

  8. 内存中 OLTP - 常见的工作负荷模式和迁移注意事项(一)

    ----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<In-Memory OLTP – Comm ...

  9. 游标-----内存中的一块区域,存放的是select 的结果

    游标-----内存中的一块区域,存放的是select 的结果          游标用来处理从数据库中检索的多行记录(使用SELECT语句).利用游标,程序可以逐个地处理和遍历一次检索返回的整个记录集 ...

随机推荐

  1. java多线程-多线程常识

    线程和进程的区别是什么?进程是一个正在运行的软件程序,打开资源管理器可以看到好多正在运行的进程,而线程则是程序中的顺序控制流,只能使用分配给程序的资源和环境.一个进程至少存在一个线程(主线程). 在j ...

  2. codeforces 465C.No to Palindromes! 解题报告

    题目链接:http://codeforces.com/problemset/problem/464/A 题目意思:给出一个长度为 n 且是 tolerable 的字符串s,需要求出字典序最小的长度也为 ...

  3. html5--3.16 button元素

    html5--3.16 button元素 学习要点 掌握button元素的使用 button元素 用来建立一个按钮从功能上来说,与input元素建立的按钮相同 button元素是双标签,其内部可以配置 ...

  4. jsp报An error has occurred. See error log for more details. Argument not valid错误

    An error has occurred. See error log for more details. Argument not valid 翻译过来是:一个错误已经发生.看到更多的细节错误日志 ...

  5. centos 安装配置kettle

    安装JDK1.8: step1 下载JDK1.8 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133 ...

  6. D3.JS V4 绘制中国地图

    参考:http://bl.ocks.org/almccon/fe445f1d6b177fd0946800a48aa59c71 http://blog.csdn.net/lzhlzz/article/d ...

  7. c++之函数值传递和引用传递解析----关键在于理解函数return的实现机制(内存分配)

    函数调用过程解析 func里的a存储在调用fun函数时开辟的栈空间里,这块栈只在调用func时对func可用,调用结束后返回的a,其实是暂存在寄存器里的(一般情况下是eax),而返回到main里时,m ...

  8. PB调用C# Windows窗体

    以下是PB中的代码:String ls_filenameLong ll_wstyle=1long ll_hwnd,ll_nShowCmdstring ls_lpOperation,ls_lpFile, ...

  9. PHP错题误区

    1,$bool = TRUE;echo gettype($bool);  //这个输出类型:booleanecho is_string($bool);  //这个用echo是不能输出布尔型的,只有va ...

  10. 【216】◀▶ IDL 字符串操作说明 (黑底)

    参考:String Processing Routines —— 字符串处理函数 参考:IDL_String Methods 01   STRING 返回字符串. 02   STRCMP 比较字符串, ...