深入解释Java7中运行UT的OutOfMemoryError: PermGen space
来源:互联网 发布:java 进程创建原语 编辑:程序博客网 时间:2024/06/05 10:30
问题描述
在Java 8被广泛应用以前,java程序员一定在某个时间点不期而遇过OutOfMemoryError: PermGen space的问题。这个异常打印已经把描述得很清楚,内存中永久代的空间不足。今天我也遇到了这个问题,或许这个问题还比较典型:一组UT代码,在经过一段时间的修改和膨胀之后,“突然”某一天在运行的时候抛出了OutOfMemoryError: PermGen space异常,导致test suite无法正常运行。经过分析,直接原因是因为使用了太多由PowerMock或Mockito mock出来的类,这些类的元文件信息大量的挤占了PermGen区的内存,导致内存不够。具体是怎么样形成的呢?我们先看看背后的知识原理。
Java的内存模型
简单说下,JVM 内存包含如下几个部分:
- 堆内存(Heap Memory): 存放Java对象
- 非堆内存(Non-Heap Memory): 存放类加载信息(class)和其它meta-data
- 其它(Other): 存放JVM 自身代码等
在Java虚拟机(JVM)内部,class文件中包括类的版本、字段、方法、接口等描述信息,还有运行时常量池,用于存放编译器生成的各种字面量和符号引用。
在过去(自定义类加载器还不是很常见的时候),类大多是”static”的,很少被卸载或收集,因此被称为“永久的(Permanent)”。同时,由于类class是JVM实现的一部分,并不是由应用创建的,所以又被认为是“非堆(non-heap)”内存。
在JDK8之前的HotSpot JVM,存放这些”永久的”的区域叫做“永久代(permanent generation)”。永久代是一片连续的堆空间,在JVM启动之前通过在命令行设置参数-XX:MaxPermSize来设定永久代最大可分配的内存空间,默认大小是64M(64位JVM由于指针膨胀,默认是85M)。永久代的垃圾收集是和老年代(old generation)捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。不过,一个明显的问题是,当JVM加载的类信息容量超过了参数-XX:MaxPermSize设定的值时,应用将会报OutOfMemoryError。
注:在JDK7之前的版本,对于HopSpot JVM,interned-strings存储在永久代(又名PermGen),会导致大量的性能问题和OOM错误。从PermGen移除interned strings的更多信息查看这里。
因此,在我们研究OutOfMemoryError: PermGen space的时候,主要考虑的是类加载超限的问题。
Class在PermGen中的存储
以下是PermGen中主要存储的内容:
- 类的基本字段
- 类的方法(Methods,包括方法的bytecodes)
- 所有类的名字
- 以对象形式指向的字符串
- 常量池信息(数据由class文件读入到PermGen)
- JVM创建的内部的对象
- Object arrays and type arrays associated with a class (e.g., an object array containing references to methods).
- 用于优化编译的各种信息(JITs)
如果没有一个直观的认识,或许你不会意识到一个class涉及到的信息有多大。
单纯的Junit Case
这是一个仅仅通过Junit运行了一个什么都没有测的用例。
public class TestPermGen{ @Before public void setUp() { BufferedReader bufferedReader = new BufferedReader( new InputStreamReader( new BufferedInputStream( System.in ) ) ); try { bufferedReader.readLine(); } catch( IOException e ) { e.printStackTrace(); } } @Test public void nothing() { return; }}
我们用Jprofiler来监控,运行时需要消耗的PermGen内存:
单单是加载Junit的框架和相关的类,已经达到了7MB的使用量。不过如果仅仅是Junit,那你运行再多的Test case,相关的类也只会被加载一次。
但如果我们用了Mockito去Mock了一些比较复杂的类,结果会如何?
使用了Mockito的Test case
public class TestPermGen{ @Mock private WorkItemImpl workItem; @Mock private EJBProvider ejbProviderMock; @Mock private WorkItemManager workItemManager; @Mock private ServiceDispatcher serviceDispatcherMock; @Before public void setUp()
4个类,将近300KB的内存。因为这些类是RunTime生成并且载入到内存当中的,因此每个Test Case Class会拥有自己的inner mock class:
因为Junit在运行时是以整个Test Suite作为一个JVM进程在运行,所以在你的Test Suite中,每个Test case mock的东西越多,整个Test Suite使用的内存就越多。
使用了MockitoJunitRunner的Test case
@RunWith( MockitoJUnitRunner.class )public class TestPermGen{ @Mock private WorkItemImpl workItem; @Mock private EJBProvider ejbProviderMock; @Mock private WorkItemManager workItemManager; @Mock private ServiceDispatcher serviceDispatcherMock;
内存疯长。这里,仍然是不同的Class,既类似的Case越多,内存越多。
- 深入解释Java7中运行UT的OutOfMemoryError: PermGen space
- Eclipse中通过Tomcat运行J2EE项目java.lang.OutOfMemoryError: PermGen space的解决方案_Tomcat服务器
- Eclipse中通过Tomcat运行J2EE项目java.lang.OutOfMemoryError: PermGen space的解决方案
- Eclipse中通过Tomcat运行J2EE项目java.lang.OutOfMemoryError: PermGen space的解决方案
- Eclipse中通过Tomcat运行J2EE项目java.lang.OutOfMemoryError: PermGen space的解决方案
- Eclipse中通过Tomcat运行J2EE项目 java.lang.OutOfMemoryError:PermGen space的解决方案
- Eclipse中通过Tomcat运行J2EE项目java.lang.OutOfMemoryError: PermGen space的解决方案
- 深入探究java.lang.OutOfMemoryError: PermGen space
- java中OutOfMemoryError:PermGen space的程序处理方法
- MyEclipse中启动Tomcat,报OutOfMemoryError: PermGen space的解决方法
- Struts2中java.lang.OutOfMemoryError: PermGen space的解决办法
- MyEclipse中启动Tomcat,报OutOfMemoryError: PermGen space的解决方法
- MyEclipse中启动Tomcat,报OutOfMemoryError: PermGen space的解决方法
- java.lang.OutOfMemoryError: PermGen space PermGen space 讲的不错
- Eclipse中通过Tomcat运行JavaWeb项目发生内存溢出:java.lang.OutOfMemoryError: PermGen space 错误的解决方案
- Eclipse中通过Tomcat运行JavaWeb项目发生内存溢出:java.lang.OutOfMemoryError: PermGen space 错误的解决方案
- Eclipse中通过Tomcat运行JavaWeb项目发生内存溢出:java.lang.OutOfMemoryError: PermGen space 错误的解决方案
- MyEclipse中启动OutOfMemoryError: PermGen space
- 基于STM32f429中ucosiii+emWin应用
- 数据仓库-HQL编码规范
- This app has been built with an incorrect configuration. Please configure your build for VectorDraw
- VMWare虚拟机通过主机shadowsocks代理上网
- uva439
- 深入解释Java7中运行UT的OutOfMemoryError: PermGen space
- Android 间断录制和播放实现
- LeetCode
- 创建注册表,设置和读取注册表中的值
- Python的基础—with...as介绍
- CMD命令——拷贝文件夹
- java 后台封装json数据
- Leetcode108——Convert Sorted Array to Binary Search Tree
- unity之跑马灯(UGUI+DOTween)