【JVM】元空间与永久代区别

永久代(PermGen)

在自定义类加载器还不是很常见的时候,类大多是static的,很少被卸载或收集,因此被成为“永久的(Permanent)”。同时,由于类class是JVM实现的一部分,并不是由应用创建的,所以又被认为是“非堆(Non-Heap)”内存。

  • 在JDK8之前的HotSpot JVM,存放这些“永久的”区域叫做“永久代(permanent generation)”。
  • 永久代是一片连续的堆空间,在JVM启动之前通过在命令行设置参数-XX:MaxPermSize
    -XX:MaxPermSize:永久代的最大可分配内存空间。默认大小64M(64位JVM由于质真膨胀,默认是85M)。当JVM加载的类信息容量超过了参数设定的值时,应用将会报OOM的错误
  • 永久代的垃圾收集和老年代(old generation)捆绑在一起,因此无论哪个满了,都会出发永久代和老年代的垃圾收集。
  • java.lang.OutOfMemoryError:PremGen space
    这里的“PermGen space”其实指的就是方法区。不过方法区和“PermGen space”又有着本质的区别。前者是JVM的规范,而后者则是JVM规范的一种实现。并且只有HotSpot才有“PermGen space”,而对于其他类型的虚拟机,如JRockit(Oracle)、J9(IBM)并没有“PermGen space”。
  • 由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出。并且JDK 1.8中参数PermSize和MaxPermSize已经失效
    1.8中的永久代被忽略
  • 移除永久代的工作从JDK 1.7就开始了。JDK 1.7中,存储在永久代的部分数据就已经转移到Java Heap或者Native Heap。但永久代仍存在于JDK 1.7中,并没有完全移除,譬如符号引用(Symbols)转移到了Native Heap;字面量(interned strings)转移到了Java Heap;类的静态变量(class statics)转移到了Java Heap。
  • G1 VS CMS:在JDK7 update 4即随后的版本中,提供了完整的支持对于Garbage-First(G1)垃圾收集器,以取代在JDK5中发布的CMS收集器。
    使用G1,PermGen仅仅在FullGC(stop-the-word,STW)时才会被收集。G1仅仅在PermGen满了或者应用分配内存的速度比G1并发垃圾收集速度快的时候才触发FullGC。
    而对于CMS收集器,通过开启布尔参数-XX:+CMSClassUnloadingEnabled来并发对PermGen进行收集。对于G1没有类似的选项,G1只能通过FullGC,stop the world,来对PermGen进行收集。

元空间(MetaSpace)

JDK8不再有PermGen,对JVM架构的改造将类元数据放到本地内存中,另外,将常量池和静态变量放到Java堆里。
HotSpot JVM将会为类的元数据明确分配和释放本地内存。在这种架构下,类元信息就突破了原来-XX:MaxPermSize的限制,现在可以使用更多的本地内存。这样就从一定程度上解决了原来在运行时生成大量类造成经常Full GC问题,如运行时使用反射、代理等。所以升级以后Java堆空间可能会增加。

  • 大部分类元数据都在本地内存中分配
  • 默认情况下,类元数据只受可用的本地内存限制(容量取决于是32/64位操作系统的可用虚拟内存大小)
  • 新参数MaxMetaspaceSize用于限制本地内存分配给类元数据的大小。如果没有指定这个参数,元空间会在运行时根据需要动态调整。
  • 僵死的类及类加载器的垃圾回收:将在元数据使用达到MaxMetaspaceSize参数的设定值时进行
  • 适时地监控和调整元空间对于减少垃圾回收频率和减少延时是很有必要的
    持续的元空间垃圾回收说明,可能存在类、类加载器导致的内存泄露或是大小设置不合适。

类元数据信息放到MetaSpace原因

  • PermGen很难调整
    PermGen中类的元数据信息在每次FullGC的时候可能会被收集,但成绩很难令人满意。而应该为PermGen分配多大的空间很难确定,因为PermSize的大小依赖于很多因素,如JVM加载的class总数,常量池的大小,方法的大小等等。
  • HotSpot中的每个垃圾收集器需要专门的代码来处理存储在PermGen中的类的元数据信息
    从PermGen分离类的元数据信息到MetaSpace,由于MetaSpace的分配具有和Java Heap相同的地址空间,因此MetaSpace和Java Heap可以无缝的管理,而且简化了FullGC的过程,以至将来可以并行的堆元数据信息进行垃圾收集,而没有GC暂停。

元空间特点

  1. 每个加载器有专门的存储空间
  2. 不会单独回收某个类
  3. 元空间里的对象的位置是固定的
  4. 如果发现某个加载器不再存货了,会把相关的空间整个回收

两者区别

元空间不在虚拟机中,使用的是本地内存;永久代使用的是JVM内存
可以通过-XX:MetaspaceSize和-XX:MaxMetaspaceSize参数来指定原空间的大小

元空间相比永久代的优势

  • 字符串常量池存在永久代中,容易出现性能问题和内存溢出
  • 类和方法的信息大小难以确定,给永久代的代销指定带来困难
  • 永久代会为GC带来不必要的复杂性
  • 方便HotSpot与其他JVM如Jrockit的集成

永久代的移除对最终用户意味着什么?

由于类的元数据可以在本地内存(native memory)之外分配,所以其最大可利用空间是整个系统内存的可用空间。这样,你将不再会遇到OOM错误,溢出的内存会涌入到交换空间。最终用户可以为类元数据指定最大可利用的本地内存空间,JVM也可以增加本地内存空间来满足类元数据信息的存储。
:永久代的移除并不意味者类加载器泄露的问题就没有了。因此,你仍然需要监控你的消费和计划,因为内存泄露会耗尽整个本地内存,导致内存交换(swapping),这样只会变得更糟。

补充问题

【JVM】元空间、堆、栈独占部份间的联系——内存角度

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值