很多开发者都在自己的系统中看到了“java.lang.OutOfMemoryError:PermGenspace”的问题。这通常是由与类加载器相关的内存泄漏和新类加载器的创建引起的,通常是在热部署代码时。与官方产品相比,这个问题在开发机上出现的频率更高。产品中最常见的“问题”是默认值太低。一个常见的解决方法是将其设置为256MB或更高。PermGen空间简介。PermGen空间的全称是PermanentGenerationspace,指的是内存的永久存储区域。先说说内存为什么会用完:这部分是用来存放Class和Meta信息的,Class是加载的时候放的。进入PermGen空间区域,它不同于存放Instances的Heap区域,所以如果你的APP会加载大量的CLASS,很可能会出现PermGen空间错误。Web服务器预编译JSP时,这种错误很常见。JVM的种类很多,比如Oralce-SunHotspot、OralceJRockit、IBMJ9、淘宝JVM(淘宝好!)等等。当然,武林之首是热点,这一点没有争议。需要注意的是PermGen空间只有Oracle-SunHotspot才有,JRockit和J9没有这个区域。元空间(MetaSpace)一个新的内存空间诞生JDK8HotSpotJVM将去掉***区,使用本地内存存储类元数据信息并称之为:元空间(Metaspace);这类似于OracleJRockit和IBMJVM非常相似,如下图所示,这意味着不再有java.lang.OutOfMemoryError:PermGen问题,您无需调整和监视内存使用...但是等等,它是那天早上说太晚了。默认情况下,这些更改是透明的,我们的下一个演示会让您知道您仍然需要注意类元数据的内存使用情况。重要的是要记住,这个新特性也不会神奇地消除由类和类加载器引起的内存泄漏。java8中元空间总结如下:PermGen空间现状这部分内存空间将被彻底清除。JVM参数:PermSize和MaxPermSize将被忽略并给出警告(如果启用时设置了这两个参数)。元空间内存分配模型大多数类元数据都分配在本地内存中。用于描述类元数据的“类”已被删除。元空间容量默认情况下,类元数据仅受可用本地内存的限制(容量取决于32位或64位操作系统的可用虚拟内存大小)。用于限制为类元数据分配的本机内存大小的新参数(MaxMetaspaceSize)。如果不指定该参数,元空间将在运行时根据需要动态调整。MetaspaceGarbageCollection当元数据使用量达到“MaxMetaspaceSize”参数设置的值时,将对死类和类加载器进行垃圾收集。及时监控和调整元空间对于减少垃圾收集频率和延迟是必要的。连续的元空间垃圾回收表明可能存在由类、类加载器或不正确的大小设置引起的内存泄漏。对Java堆内存的影响一些杂项数据已移至Java堆空间。升级到JDK8后,你会发现Java堆空间变大了。元空间监控元空间使用情况可以从HotSpot1.8详细的GC日志输出中获取。Jstat和JVisualVM这两个工具在使用b75版本测试的时候已经更新了,但是还是可以看到老PermGen空间的样子。上面已经在理论上进行了充分的解释,让我们通过“泄漏”程序来观察新的内存空间……执行测试:使用JDK1.7运行Java程序,监控耗尽默认PermGen内存空间85MB。使用JDK1.8运行Java程序,监控新的Metaspace内存空间的动态增长和垃圾回收过程。使用JDK1.8运行Java程序,模拟“MaxMetaspaceSize”参数设置的128MBMetaspace内存空间耗尽。先创建一个模拟PermGenOOM的代码publicclassClassA{publicvoidmethod(Stringname){//donothing}}上面是一个简单的ClassA,编译成class字节码放在D:/classes下,在测试代码中使用URLClassLoader加载上面这个类型的class被编译成class/***SimulatePermGenOOM*@authorbenhail*/publicclassOOMTest{publicstaticvoidmain(String[]args){try{//准备urlURLurl=newFile("D:/classes").toURI().到网址();URL[]urls={url};//获取关于类型加载的JMX接口ClassLoadingMXBeanloadingBean=ManagementFactory.getClassLoadingMXBean();//用于缓存类加载器ListclassLoaders=newArrayList();while(true){//加载类型并缓存类加载器实例数、当前有效类型数、已经卸载的类型数)System.out.println("total:"+loadingBean.getTotalLoadedClassCount());System.out.println("active:"+loadingBean.getLoadedClassCount());System.out.println("卸载:"+loadingBean.getUnloadedClassCount());}}赶上(Exceptione){e.printStackTrace();}}}虚拟机参数设置如下:-verbose-verbose:gc设置-verbose参数是获取类型加载和卸载的信息-verbose:gc是获取垃圾回收的信息#p#JDK1.7@64-bit–PermGenExhaustionTestJava1.7的PermGen默认空间是85MB(或者可以通过-XX:MaxPermSize=XXXm指定)从上面JVisualVM的截图可以看出:当加载超过6个10000个类后,PermGen就被耗尽了.我们也可以通过程序和GC输出来观察耗尽过程。程序输出(提取部分)...[LoadedClassAfromfile:/D:/classes/]total:64887active:64887unloaded:0[GC245041K->213978K(536768K)??,0.0597188secs][FullGC213978K->211425K(644992K),0.6456638secs][GC211425K->211425K(656448K),0.0086696secs][FullGC211425K->211411K(731008K),0.6924754secs][GC211411K->211411K(726508K)89。............java.lang.OutOfMemoryError:PermGenspaceJDK1.8@64-bit–MetaspacesizedynamicadjustmentTestJavaMetaspacespace:unlimited(default)从上面的截图可以看出,JVMMetaspace已经动态扩展了,本地内存的使用从20MB增加到646MB,以满足程序中不断增长的类数据内存使用需求。我们还可以观察JVM垃圾收集事件——试图销毁死类或类加载器对象。但是,由于我们程序的漏洞,JVM不得不动态扩展Metaspace内存空间。该程序加载了超过100,000个没有OOM事件的类。JDK1.8@64-bit–MetaspacelimitedtestJava的Metaspacespace:128MB(-XX:MaxMetaspaceSize=128m)从上面JVisualVM的截图可以看出:当类加载超过20000个时,Metaspace被耗尽;和JDK1.7runtime很相似。我们也可以通过程序和GC输出来观察耗尽过程。另一个有趣的现象是保留的本机内存占用量是设置的最大大小的两倍。这可能表明,如果可能,微调元空间容量大小调整策略以避免浪费本地内存。在Java程序的输出中可以看到以下异常。[LoadedClassAfromfile:/D:/classes/]total:21393active:21393unloaded:0[GC(MetadataGCThreshold)64306K->57010K(111616K),0.0145502secs][FullGC(MetadataGCThreshold)57010K->56810K(1224108K),0.0.javasecs6.OutOfMemoryError:Metaspace在设置MaxMetaspaceSize的情况下,该空间的内存仍然会被耗尽,进而导致“java.lang.OutOfMemoryError:Metadataspace”错误。因为类加载器泄漏仍然存在,而且Java通常不想无限期地消耗本机内存,因此设置类似于MaxPermSize的限制似乎是合理的。总结以前,不管需要与否,JVM都会吃掉那块空间……如果设置得太小,JVM就会死掉;如果设置太大,JVM会浪费这些内存。理论上来说,现在不需要关注这个,因为JVM会在运行时自动调整到“合适的大小”;为了提高FullGC的性能,在FullGC期间,不需要在Metadata和Metadata指针之间进行扫描,不要小看这几纳秒;隐患是如果程序有内存泄漏,比如OOMTest,如果metaspace空间不断扩大,机器内存就会不足,所以还是需要进行必要的调试和监控。原文链接:http://my.oschina.net/benhaile/blog/214159