五、JVM之堆内存
堆结构分代图
堆结构分代的意义
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控制,而由系统实际可用空间来控制。
五、JVM之堆内存的更多相关文章
- jvm虚拟机--堆内存
reserved 保留区域 堆 所有对象实例都在这里分配内存. 是垃圾收集的主要区域("GC 堆").现代的垃圾收集器基本都是采用分代收集算法,主要思想是针对不同的对象采取不同的垃 ...
- JVM中堆内存和栈内存的区别
Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...
- JVM的堆内存泄漏排查-性能测试
JVM异常说明 https://testerhome.com/articles/24259 一文中已介绍了,JVM每个运行时区域--程序计数器 .Java虚拟机栈.本地方法栈.Java堆.方法区.直接 ...
- JVM之堆内存(年经代,老年代)
一.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我 ...
- 【转】JVM 堆内存设置原理
堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...
- JVM 堆内存和非堆内存
转载自:http://www.importnew.com/27645.html 堆和非堆内存 按照官方的说法:“Java 虚拟机具有一个堆(Heap),堆是运行时数据区域,所有类实例和数组的内存均从此 ...
- [转]JVM 堆内存设置原理
堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...
- JVM 堆内存设置原理
堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...
- JVM 堆内存设置原理(转)
堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...
随机推荐
- 如何在 Linux 中找出 CPU 占用高的进程
1) 怎样使用 top 命令找出 Linux 中 CPU 占用高的进程 在所有监控 Linux 系统性能的工具中,Linux 的 top 命令是最好的也是最知名的一个.top 命令提供了 Linux ...
- django的自定义权限
最近在写发布系统,涉及到权限的控制 参考 黄小墨同学的博客实现了 如下 1:定义一张权限控制的表 [root@localhost app01]# tailf -25 models.py class P ...
- Apache 容器 Directory Location Files 及htaccess文件
配置段容器的类型 相关模块 core mod_proxy 相关指令 <Directory> <DirectoryMatch> <Files> <FilesMa ...
- php-fpm.conf.default配置文件
;;;;;;;;;;;;;;;;;;;;; ; FPM Configuration ; ;;;;;;;;;;;;;;;;;;;;; ; All relative paths in this confi ...
- 解决github图片不显示的问题
修改hosts C:\Windows\System32\drivers\etc\hosts 在文件末尾添加: # GitHub Start 192.30.253.112 Build software ...
- Jenkins自动化构建vue项目然后发布到远程Linux服务器
部署Jenkins参照另一篇博客: centos7安装Jenkins及其卸载 一.jenkins相关插件的安装 1.安装Publish Over SSH插件用于SSH连接远程的服务器. 登录 jenk ...
- js 常用总结
1.截取字符串 var a="/s/d"; console.log(a.substr(0,a.indexOf("/",1))) // 得到/s 2. // ...
- IT运维大会精华回顾 等保2.0时代掌控万物互联
10月24日,由<网络安全和信息化>杂志社.IT运维网联合主办的“2019(第十届)IT运维大会”在北京新世纪日航酒店成功举行. 随着大数据.云计算.物联网.互联网+等快速发展,IT系统架 ...
- clr via c# 程序集加载和反射(2)
查看,clr via c# 程序集加载和反射(1) 8,发现类型的成员: 字段,构造器,方法,属性,事件,嵌套类型都可以作为类型成员.其包含在抽象类MemberInfo中,封装了所有类型都有的一组属性 ...
- JavaScript-迭代器模式
迭代器模式 顺序访问一个集合 使用者无需知道集合内部结构(封装) jQuery 示例 <!DOCTYPE html> <html> <head> <meta ...