zoukankan      html  css  js  c++  java
  • Permanent Generation Removal Overview(译文)

    英文原稿:http://vdisk.weibo.com/s/vxGdGZEZTEjk

    中文整理稿:http://it.deepinmind.com/gc/2014/05/14/metaspace-in-java-8.html

    其实上面的整理稿,是针对这篇英文文稿的翻译兼整理,但是感觉有点乱,有点强迫症,所以干脆自己来翻译。关于vm相关性能数据的监控部分略掉了,此稿件主要是介绍perm gen的设计与移除,以及移除perm gen之后新的内存模型,所以后面关于内存的调优还有性能的监测都过于简单,如果想了解,可以去看周志明先生的《深入理解Java虚拟机》,里面对jstat等工具有更多的介绍。

    翻译:

        Oracle HotSpot JVM中的perm gen保存了HotSpot用于描述Java对象(Java objects)的元数据(metadata)。perm gen在Full GC中会和Java堆(Java Heap)一起经历垃圾回收。perm gen在JDK8中的HotSpot中,已经被移除了。本节简单的描述了perm gen及移除它的动机。还讨论了移除perm gen可能对Java程序的执行造成的多方面的影响。

     

     

    议题

    • 什么是perm gen
    • 现在的元数据在哪儿
    • 压缩的类指针
    • 新的调节参数
    • Memory Pool MXBeans

     

    什么是perm gen

    • 全名permanent generation
    • 是Java Heap中用于存储虚拟机类的元数据的区域
    • Java类在HotSpot中的内在表现
      • 类的结构信息,字段,名字
      • 方法的汇编信息和字节码
      • Vtables(虚函数表)
      • 常量池和符号解析

     

    含有perm gen的vm内存分布示意图:

     

     

    PermGen 大小

    • 1.受限于参数MaxPermSize(默认是64M-85M)
    • 2.需要Java Heap中连续的存储空间:如果分配的堆空间不连续,那么从old gen和perm gen定位指向新对象的引用,代价就会更大,而且也会更复杂。(card table   remembered set)
    • 3.一旦耗尽,就会抛异常
      • 清除引用来触发类卸载
      • 配置更大的MaxPermSize
    • 4.perm gen的大小依赖于类的数量,方法的大小,以及常量池的大小

     

     

    为什么要移除PermGen

    • 启动的时候就要指定大小,难以调优:MaxPermSize要设多大?
    • HotpSpot内部类型是Java对象,可能会在Full GC中移动,对应用程序来说,不透明,并且非强类型,很难调试,需要用于存储元数据的空间
    • 简化Full GC
      • 为每个收集器的元数据指定迭代器
    • 希望能并发的回收类型数据空间,而不是在GC停顿期间
    • 使受限于permgen的未来的改进成为可能

     

    元数据去哪儿了?

     

     

    得益于Java语言特性:类及相关元数据的生命周期和累加载器相匹配

     

    每一个加载器的存储空间

    • 仅线性分配
    • 没有单独的回收(除非RedefineClasses和类加载失败)
    • 没有GC扫描和整理
    • 不需要重新安置元数据空间对象
    • 当GC发现类加载器死亡,则整个空间一起回收

     

    这些存储空间的集体称为Metaspace

     

     

    Metaspace 分配

    • 为元数据分配多个映射虚拟内存空间
    • 为每个类加载器分配块状空间列表
      • 块的大小依赖于类加载器的大小
      • 为sun/reflect/DelegatingClassLoader, JSR292匿名类的加载器分配较小的块
    • 归还内存块,以释放块状列表
    • 当被清空的时候,归还虚拟内存空间
    • 设计诸多策略来减少碎片

     

    如下图:

     

    (图中CL为类加载器,Boot CL为启动类加载器,vs1,vs2,vs3为虚拟内存空间,黄色的块为元数据块)

     

    Java对象内存分配

     

    堆上对象有指向Metaspace中自己类信息的指针—>_klass

    在64位平台上,为了压缩JVM对象中的类指针,引入了“压缩类指针空间”(对象中的_klass变为4字节,指向压缩类空间中的数据,该数据再指向Metaspace中的类信息)

     

     

    压缩指针(压缩类指针,压缩对象指针)

    • 默认是为了64位平台
    • 使用-XX:+UseCompressedOops 来压缩对象指针
      • oops是指普通对象指针
      • Java堆中对象的对象指针被压缩到32bit
      • 使用堆基地址(如果在低26G内存空间中,为0)即,指针的偏移量针对于堆的基地址 
    • 使用-XX:+UseCompressedClassPointers 压缩类指针
      • 对象的类指针(_klass)被压缩至32bit
      • 使用类指针压缩空间的基地址

    Metaspace与类压缩空间的对比

    • 类压缩空间只包含像接口指针(InstanceKlass),数组指针(ArrayKlass)等元数据
      • 仅当UseCompressedClassPointers为true的时候会这样
      • 为了性能问题,这里还保存了Java 虚方法表
      • 我们仍然在减少这个元数据类型 
    • 而Metaspace包含了元数据的其他所有的数据,这可能比较大,如方法,字节码,常量池

    GC性能的提升

    • 在Full GC,元数据到元数据的指针不需要扫描
      • 一大堆元数据扫描的复杂代码(尤其在CMS)都被删除了
    • 元数据空间包含较少的指向Java Heap的指针
      • 指向java/lang/Class对象的指针存储在类元数据中
      • 数据类元数据中,有指向其成员类Class对象的指针
      • 我们要移除这些 
    • 元数据不再有整理消耗
    • 减少了根扫描(不扫描VM已加载类的字典和其他内部的哈希表)
    • Full GC的时间将会缩短(不同情况下可能会有所不同)
    • 在G1中可以在并发标记之后进行类卸载
    • 可以调优

     

    调优标志

    MaxMetaspaceSize

     

    • -XX:MaxMetaspaceSize={unlimited}
    • Metaspace受机器内存的限制
    • 在虚拟内存切换频繁和本地内存分配失败之前,限制类元数据使用的内存
      • 如果类加载器内存可能泄漏
      • 如果在32位平台上,地址空间可能耗尽
    • MaxMetaspaceSize是指Metaspace和压缩类指针空间的总和 

    MetaspaceSize

    • 初始大小为21mb,超过这个值,将进行Full GC来回收类
      • GC的相关操作用于检测已死的类加载器,和未加载的类
    • 如果在启动阶段发生了过多的GC,则需要设置一个高点的限制
    • 可以使用与PermSize相同的值,来延缓初始GC
    • 在下次Metaspace GC之前,High water mark会随着接下来合理数量的头空间的收集而增高

    CompressedClassSpaceSize

    • 当使用了-XX:+UseCompressedClassPointers 才有效
    • -XX:CompressedClassSpaceSize=1G 
    • 因为这个空间只能在启动的时候设置,所以一开始就设置大一点
    • 不使用的时候,不会分配
    • 未来的工作,是要使这块空间可增长
      • 不需要连续,只需要从基地址可达
      • 更倾向于将更多的类元数据移到Metaspace中 
    • 未来可能会以性能为主导
      • PredictedLoadedClassCount (该标志目前处于试验性):用于设置其他JVM内部数据结构的大小,像已加载类的字典
    • 开发者可能会发现对于CompressedClassSpaceSize和UseCompressedClassPointers的不同命名。但在JDK-8015107中已经设定,对metaspace的概念,需要使用统一的命名方式

     

    可以通过-XX:+PrintGCDetails and -XX:+PrintHeapAtGC来查看metaspace的使用情况

     

    PermGen内存池以前在内存管理中属于Heap内存池的列表中,现在移除了

     

    总结:

    • HotSpot 元数据现在存在元空间中
      • 压缩类指针空间仍然需要被设定,但是要大一些
    • 有调优标志,虽然并不是必须要使用的
    • 这种改变使得其他优化与特性成为可能
      • 共享类数据
      • 新生代优化,G1进行类卸载
      • 元数据减少

     

     

    译者有话说:

     

    表示有些地方,我没看懂,不过总的还是有收获的。而且,我感觉是指导性文档,抠字眼就没必要了。最近一直在看JVM的相关内容,总结一句话,发展时间太久,各种词汇乱用,导致哪哪儿都模棱两可。

    比如,现在从一些较官方的文档来看,Java Heap和我们常说的java堆是不同的,我们常说的java堆只包含新生代和老年代,是用来存储对象实例数据的,但是Java Heap是包括perm gen在内的GC作用的整个堆空间。有人说,这有神马影响吗?没影响的时候没影响,有影响的时候,真是搞脑子。

     

    简单点概括

     

    过去类的元数据存储在perm gen,作为Java Heap的一部分,使用instanceKlass,instanceKlassKlass,klassKlass(详见R大关于perm gen数据的追踪博客),接受GC传统意义上的扫描。弊端:内存受限,容易溢出;空间回收性能低等。现在的元数据存在元空间中。元空间由多个虚拟内存空间构成,每个虚拟内存空间又被划分为不同大小的块。以类加载器为源头,随着类的不断加载,不断从虚拟内存空间中分配块空间,从而使每个类加载器对应了一个块列表。当GC检测到某个类加载器已死,就整体释放整个列表,回收内存。

     

    至于压缩类空间,出于多个原因考虑,主要有两个。第一,在64位平台,指针膨胀导致内存浪费,使用压缩类指针,压缩类指针空间基地址的概念,继续使用32位指针寻址;第二,这样一个空间还可以存储部分元数据,以提高相应性能。

     

     

     

  • 相关阅读:
    XAF 有条件的对象访问权限
    XAF 顯示 UnInplace Report(設置自定義條件顯示報表,不是根據選擇ListView記錄條件顯示報表)
    XAF 如何自定义PivotGrid单元格显示文本?
    XAF 如何布局详细视图上的按钮
    XAF How to set size of a popup detail view
    XAF Delta Replication Module for Devexpress eXpressApp Framework
    XAF 帮助文档翻译 EasyTest Basics(基础)
    XAF 用户双击ListView记录时禁止显示DetailView
    XAF How to enable LayoutView mode in the GridControl in List Views
    XAF 如何实现ListView单元格批量更改?
  • 原文地址:https://www.cnblogs.com/zhulin-jun/p/6516292.html
Copyright © 2011-2022 走看看