JVM---运行时区域异常OutOfMemoryError
这些异常最好不好出现,下面复现,只是为了让我们对这些异常有一个直观的认识
堆溢出
可以通过参数-XX:+PrintCommandLineFlags,查看堆初始值和最大值,若初始值过小,堆会进行自动扩容(扩容前会触发GC),频繁的GC或者扩容肯定是消耗时间的,因此看系统执行情况,合理配置初始堆大小
为复现堆OutOfMemoryError,可设置初始堆70M,即-Xms70m,最大堆大小70M,即-Xmx70m,程序代码
public class OutOfMemoryTest { public static void main(String[] args) { List<OutOfMemoryTest> list = new ArrayList<>(); for (;;){ list.add(new OutOfMemoryTest()); } } }
运行结果,显示JAVA堆溢出
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3204) at java.util.Arrays.copyOf(Arrays.java:3175) at java.util.ArrayList.grow(ArrayList.java:246) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:220) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:212) at java.util.ArrayList.add(ArrayList.java:443) at main.JVMTEST.OutOfMemoryTest.main(OutOfMemoryTest.java:10)
引申,若将代码做如下修改,则不会出现OutOfMemoryError,这个是怎样造成的呢
public class OutOfMemoryTest { public static void main(String[] args) { List<OutOfMemoryTest> list = new ArrayList<>(); for (;;){ list.add(new OutOfMemoryTest()); System.gc(); } } }
使用jvisualvm观察,发现堆空间好像都没怎么变动过,程序也没有出现OutOfMemoryError。实际上就是不断gc,还耗时。实际上长时间的话,迟早OutOfMemoryError。
对堆空间进行分析,可以设置-XX:+HeapDumpOnOutOfMemoryError生成内存堆转储快照,以方便后续进行分析(一般情形下不用设,如果出现堆OutOfMemoryError,而又无法直接观察出来,可以进行设置)。
这个地方需要指出,若在堆上看到OutOfMemoryError,需要我们确认时内存溢出还是内存泄露产生的,其实就是看对象是不是必须还存活者。比如这个list实际上是一个实例对象,但是使用完了之后一直不进行回收而占用堆空间(这种就是对象不是必须或者),这样可能就造成内存泄漏。别人博客让也写了OutOfMemoryError,且做了一个思维导图https://blog.csdn.net/baidu_37107022/article/details/88862371,我觉得还是可以借鉴的,我就不直接复制出来了。
虚拟机栈和本地方法栈溢出
Hot Spot将两个区域合二为一。设置参数如下:
-Xoss(设置本地方法栈大小),实际上无效
-Xss(设计栈容量)
JAVA虚拟机规范中描述了两种异常
OutOfMemoryError 栈无法申请到足够空间抛出(实现时,没看到出现,没有写例子)
StackOverFlowError 线程请求的栈深度大于虚拟机所允许的最大深度
vm参数-Xss80k
public class StackOverflowTest {
int length;
public int getLength(){
return this.length;
}
public void test(){
this.length++;
test();
}
public static void main(String[] args) {
StackOverflowTest stackOverflowTest = new StackOverflowTest();
try{
stackOverflowTest.test();
}catch (Throwable t){
System.out.println(stackOverflowTest.getLength());
t.printStackTrace();
}
}
}
方法区和运行时常量池溢出
jdk1.8之前
Hot Spot虚拟机将方法区使用永久代实现,可以设置-XX:PermSize和-XX:MaxPermSize设置(我机器上安装的时JDK1.8,我就不进行复现了)
jdk1.8往后
Hot Spot虚拟机将方法区使用元空间实现,可设置-XX:MaxMetaspaceSiz
vm参数设置:-XX:MaxMetaspaceSize=10m
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.8</version> </dependency>
public class MethodAreaOutOfMemoryError { public static void main(String[] args) { for(;;){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(MethodAreaOutOfMemoryError.class); enhancer.setUseCache(false); enhancer.setCallback((MethodInterceptor)(obj, method, args1, proxy)-> proxy.invokeSuper(obj,args1) ); enhancer.create(); } } }
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:340) at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:467) at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:336) at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492) at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:114) at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291) at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480) at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305) at outofmemoryerror.MethodAreaOutOfMemoryError.main(MethodAreaOutOfMemoryError.java:15)
本机直接内存溢出(并不属于虚拟机运行时区域,不过也有OutOfMemory)
可以通过-XX:maxDirectMemorySize指定,如果不指定,默认与Java堆最大值(-Xmx)相同
VM参数-XX:MaxDirectMemorySize=500k或者-Xmx2m
public class DirectorBufferTest { private static final int _1MB =1024*1024; public static void main(String[] args) { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_1MB); } }
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory at java.nio.Bits.reserveMemory(Bits.java:658) at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at main.JVMTEST.DirectorBufferTest.main(DirectorBufferTest.java:9)
友情链接:CGLIB https://blog.csdn.net/gyshun/article/details/81000997
元空间 https://www.infoq.cn/article/Java-permgen-Removed
内存OutOfMemoryhttps://blog.csdn.net/baidu_37107022/article/details/88862371
posted on 2020-04-20 21:51 xingshouzhan 阅读(209) 评论(0) 编辑 收藏 举报