堆结构分代图

堆结构分代的意义

  Java虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代、老年代和永久代(对HotSpot虚拟机而言),这就是JVM的内存分代策略。
  堆内存是虚拟机管理的内存中最大的一块,也是垃圾回收最频繁的一块区域,我们程序所有的对象实例都存放在堆内存中。给堆内存分代是为了提高对象内存分配和垃圾回收的效率。试想一下,如果堆内存没有区域划分,所有的新创建的对象和生命周期很长的对象放在一起,随着程序的执行,堆内存需要频繁进行垃圾收集,而每次回收都要遍历所有的对象,遍历这些对象所花费的时间代价是巨大的,会严重影响我们的GC效率。
  有了内存分代,情况就不同了,新创建的对象会在新生代中分配内存,经过多次回收仍然存活下来的对象存放在老年代中,静态属性、类信息等存放在永久代中,新生代中的对象存活时间短,只需要在新生代区域中频繁进行GC,老年代中对象生命周期长,内存回收的频率相对较低,不需要频繁进行回收,永久代中回收效果太差,一般不进行垃圾回收,还可以根据不同年代的特点采用合适的垃圾收集算法。分代收集大大提升了收集效率,这些都是内存分代带来的好处。

堆结构分代

​ Java虚拟机将堆内存划分为新生代、老年代和永久代,永久代是HotSpot虚拟机特有的概念(JDK1.8之后为metaspace替代永久代),它采用永久代的方式来实现方法区,其他的虚拟机实现没有这一概念,而且HotSpot也有取消永久代的趋势,在JDK 1.7中HotSpot已经开始了“去永久化”,把原本放在永久代的字符串常量池移出。永久代主要存放常量、类信息、静态变量等数据,与垃圾回收关系不大,新生代和老年代是垃圾回收的主要区域。

新生代(Young Generation)

  新生成的对象优先存放在新生代中,新生代对象朝生夕死,存活率很低,在新生代中,常规应用进行一次垃圾收集一般可以回收70% ~ 95% 的空间,回收效率很高。
  HotSpot将新生代划分为三块,一块较大的Eden(伊甸)空间和两块较小的Survivor(幸存者)空间,默认比例为8:1:1。划分的目的是因为HotSpot采用复制算法来回收新生代,设置这个比例是为了充分利用内存空间,减少浪费。新生成的对象在Eden区分配(大对象除外,大对象直接进入老年代),当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC。
  静态版GC开始时,对象只会存在于Eden区,From Survivor区和To Survivor区是空的(作为保留区域)。GC进行时,Eden区中所有存活的对象都会被复制到From Survivor区。若From Survivor区也满了,再对该区进行垃圾回收,然后把所有存货的对象复制到To Survivor区。那如果To Survivor区也满了呢?再移动到养老区。若养老区也满了,那么这个时候将产生Major GC(FullGC),进行养老区的内存清理。若养老区执行了Full GC之后发现依然无法进行对象的保存,就会产生OOM异常“OutOfMemoryError”,通常Full GC 所消耗的性能是Minor GC的十倍以上。

动态版首先,当Eden区满的时候会触发第一次GC,把还活着的对象拷贝到SurvivorFrom区,当Eden区再次触发GC的时候会扫描Eden区和From区,对这两个区进行垃圾回收,经过这次回收后还存活的对象,则直接赋值到To区域(如果有对象的年龄已经达到了老年的标准,则赋值到老年代区),同时把这些对象的年龄加+1。然后,清空Eden和From区中的对象,接着, From Survivor区和To Survivor区会交换它们的角色,也就是新的To Survivor区就是上次GC清空的From Survivor区,新的From Survivor区就是上次GC的To Survivor区,总之,不管怎样都会保证To Survivor区在一轮GC后是空的。部分对象会在From和To区域中复制来复制去,如此交换15次(由JVM参数MaxTenuringThreshold决定默认是15),最终如果还是存活,就存入老年代。

老年代(Old Generationn)

​ 在新生代中经历了多次(具体看虚拟机配置的阀值)GC后仍然存活下来的对象会进入老年代中。老年代中的对象生命周期较长,存活率比较高,在老年代中进行GC的频率相对而言较低,而且回收的速度也比较慢。

永久代(Permanent Generationn)(JDK1.8后移除)

​ 永久代存储类信息、常量、静态变量、即时编译器编译后的代码等数据。

​ 永久存储区是一个常驻内存区域,用于存放JDK自身所携带的Class,Interface的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM才会释放此区域所占用的内存。

元空间(Meta Space)

元空间是JDK 1.8 之后才有的,功能和永久代类似。唯一到的区别是,永久代使用的是JVM的堆内存空间,而元空间使用的是物理内存,直接受到本机的物理内存限制。

因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入native memory,字符串池和类的静态变量放入java堆中,这样可以加载多少类的元数据就不再由MaxPermSize控制,而由系统实际可用空间来控制。

最新文章

  1. 弱占优策略--Weakly Dominant Strategy
  2. 快速排序(python版)
  3. 从零开始学ios开发(二):Hello World!来啦!
  4. codeVS1966 乘法游戏
  5. HDU 1513 Palindrome
  6. Layout Resource官方教程(4)<include>与<merge>
  7. poj3468(线段树 边覆盖)
  8. 关于广义后缀树(多串SAM)的总结
  9. Struts2默认拦截器配置
  10. 如何A掉未来程序改
  11. 流动python - 什么是魔术方法(magic method)
  12. 实战深度学习OpenCV(三):视频实时canny边缘检测
  13. MVC架构模式详细说明
  14. 在同时满足if 和 else 条件的情况下,输出所需的内容。
  15. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [一] 初衷与架构设计
  16. PHP json_encode函数中需要注意的地方
  17. 4698: Sdoi2008 Sandy的卡片
  18. linux系统 python升级创建虚拟环境
  19. RandomForest随机森林总结
  20. Power Shell 学习笔记

热门文章

  1. grep知识及常用用法梳理
  2. linux中的正则表达式知识梳理
  3. css实现文字过长显示省略号的方法
  4. 北京智和信通IT运维管理系统二次开发服务提供商
  5. NCE L4
  6. git系列之---将本地的项目添加到码云仓库
  7. ​Microchip SPI串行SRAM和NVSRAM器件
  8. jmeter-json提取器提取的内容含”引号
  9. VS自定义模板-以自定义类模板为样例
  10. svn cleanup 失败问题解决