在过去(当自定义类加载器使用不普遍的时候),类几乎是"静态的"并且很少被卸载和回收,因此类也可以被看成"永久的”。另外由于类作为JVM实现的一部分,它们不由程序来创建,因为它们也被认为是"非堆"的内存。

在JDK8之前的HotSpot虚拟机中,类的这些"永久的"数据存放在一个叫做永久代的区域。永久代一段连续的内存空间,我们在JVM启动之前可以通过设置-XX:MaxPermSize的值来控制永久代的大小,32位机器默认的永久代的大小为64M,64位的机器则为85M。永久代的垃圾回收和老年代的垃圾回收是绑定的,一旦其中一个区域被占满,这两个区都要进行垃圾回收。但是有一个明显的问题,由于我们可以通过‑XX:MaxPermSize 设置永久代的大小,一旦类的元数据超过了设定的大小,程序就会耗尽内存,并出现内存溢出错误(OOM)。

备注:在JDK7之前的HotSpot虚拟机中,纳入字符串常量池的字符串被存储在永久代中,因此导致了一系列的性能问题和内存溢出错误。

这边转自 http://www.cnblogs.com/moonandstar08/p/5001914.html

这项改动是很有必要的,因为对永久代进行调优是很困难的。永久代中的元数据可能会随着每一次Full GC发生而进行移动。并且为永久代设置空间大小也是很难确定的,因为这其中有很多影响因素,比如类的总数,常量池的大小和方法数量等。

同时,HotSpot虚拟机的每种类型的垃圾回收器都需要特殊处理永久代中的元数据。将元数据从永久代剥离出来,不仅实现了对元空间的无缝管理,还可以简化Full GC以及对以后的并发隔离类元数据等方面进行优化。

新增加的metaspace:

持久代的空间被彻底地删除了,它被一个叫元空间的区域所替代了。持久代删除了之后,很明显,JVM会忽略PermSize和MaxPermSize这两个参数,还有就是你再也看不到java.lang.OutOfMemoryError: PermGen error的异常了。

JDK 8的HotSpot JVM现在使用的是本地内存来表示类的元数据,这个区域就叫做元空间。

元空间的特点:

充分利用了Java语言规范中的好处:类及相关的元数据的生命周期与类加载器的一致。

每个加载器有专门的存储空间

只进行线性分配

不会单独回收某个类

省掉了GC扫描及压缩的时间

元空间里的对象的位置是固定的

如果GC发现某个类加载器不再存活了,会把相关的空间整个回收掉

元空间的内存分配模型

绝大多数的类元数据的空间都从本地内存中分配

用来描述类元数据的类也被删除了

分元数据分配了多个虚拟内存空间

给每个类加载器分配一个内存块的列表。块的大小取决于类加载器的类型; sun/反射/代理对应的类加载器的块会小一些

归还内存块,释放内存块列表

一旦元空间的数据被清空了,虚拟内存的空间会被回收掉

减少碎片的策略

http://www.infoq.com/cn/articles/Java-PERMGEN-Removed

http://www.jianshu.com/p/7b88aa16c2f6

http://www.cnblogs.com/paddix/p/5309550.html