Java学习(一):JVM内存区域与内存溢出异常
2018-02-10 00:00
459 查看
摘要: 实践是检验整理的唯一标准
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁。根据《Java虚拟机规范(Jave SE 7 版)》的规定,Java虚拟机所管理的内存将会包括一下几个运行时数据区域,如下图所示:
(2) Java虚拟机栈
(3) 本地方法栈
(4) Java堆
(5) 方法区
(6) 运行时常量池
(7) PermGen (永久代) 与 Metaspace (元空间)
(8) Java堆溢出
(9) 虚拟机栈和本地方法栈溢出
(10) 方法区与常量池溢出
参数控制:-Xms20m -Xmx20m -XX:+PrintGCDetails
参数控制:-Xss128k -XX:+PrintGCDetails
参数控制:
JDK1.7:-XX:PermSize=10m -XX:MaxPermSize=10m -XX:+PrintGCDetails
JDK1.8:-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m -XX:+PrintGCDetails
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁。根据《Java虚拟机规范(Jave SE 7 版)》的规定,Java虚拟机所管理的内存将会包括一下几个运行时数据区域,如下图所示:
目录大纲:
(1) 程序计数器(2) Java虚拟机栈
(3) 本地方法栈
(4) Java堆
(5) 方法区
(6) 运行时常量池
(7) PermGen (永久代) 与 Metaspace (元空间)
(8) Java堆溢出
(9) 虚拟机栈和本地方法栈溢出
(10) 方法区与常量池溢出
1、程序计数器
程序计数器是一块较小的内存空间,它可以看成是当前线程所执行的字节码的行号指示器。程序计数器记录线程当前要执行的下一条字节码指令的地址。由于Java是多线程的,所以为了多线程之间的切换与恢复,每一个线程都需要单独的程序计数器,各线程之间互不影响。这类内存区域被称为“线程私有”的内存区域。2、Java虚拟机栈
Java虚拟机栈是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。虚拟机栈可能出现两种异常:由线程请求的栈深度过大超出虚拟机所允许的深度而引起的StackOverflowError异常;以及由虚拟机栈无法提供足够的内存而引起的OutOfMemoryError异常。3、本地虚拟机栈
本地方法栈与虚拟机栈类似,他们的区别在于:本地方法栈用于执行本地方法(Native方法);虚拟机栈用于执行普通的Java方法。在HotSpot虚拟机中,就将本地方法栈与虚拟机栈做在了一起。 本地方法栈可能抛出的异常同虚拟机栈一样。4、Java堆
Java堆是被所有线程共享的一块内存区域,此内存区域的唯一目的就是存放对象实例。Java堆是垃圾收集器管理的主要区域,从内存回收的角度来看,Java堆中可以细分为:新生代(Eden空间、From Survivor空间、To Survivor空间)、老年代、永久代(JDK8移除)。5、方法区
方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。6、运行时常量池
运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。7、永久代与元空间
在JDK1.8中使用元空间代替永久代,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。8、Java堆溢出
Java堆用来存储对象实例,只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象到达最大堆的容量限制后就会产生内存溢出异常。参数控制:-Xms20m -Xmx20m -XX:+PrintGCDetails
package com.xusg.study.jvm.oom; import java.util.ArrayList; import java.util.List; /** * 堆内存溢出 * VM Args:-Xms20m -Xmx20m -XX:+PrintGCDetails * * @Author Xusg * @Date 18/2/7 14:46 */ public class HeapOOM { static class OOMObject { } public static void main(String[] args) { List<OOMObject> oomObjects = new ArrayList<>(); while (true) { oomObjects.add(new OOMObject()); } } }
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3210) at java.util.Arrays.copyOf(Arrays.java:3181) at java.util.ArrayList.grow(ArrayList.java:261) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227) at java.util.ArrayList.add(ArrayList.java:458) at com.xusg.study.jvm.oom.HeapOOM.main(HeapOOM.java:24)
9、虚拟机栈和本地方法栈溢出
HotSpot 虚拟机中并不区分虚拟机栈和本地方法栈。如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。如果虚拟机在扩展栈时,无法申请到足够的内存空间,则将抛出OutOfMemoryError异常。参数控制:-Xss128k -XX:+PrintGCDetails
package com.xusg.study.jvm.oom; /** * 虚拟机栈异常 * VM Args:-Xss128k * * @Author Xusg * @Date 18/2/10 11:48 */ public class StackOOM { public void stackLeak() { stackLeak(); } public static void main(String[] args) { StackOOM stackOOM = new StackOOM(); try { stackOOM.stackLeak(); } catch (Exception e) { e.printStackTrace(); } } }
Exception in thread "main" java.lang.StackOverflowError at com.xusg.study.jvm.oom.StackOOM.stackLeak(StackOOM.java:15) at com.xusg.study.jvm.oom.StackOOM.stackLeak(StackOOM.java:15) at com.xusg.study.jvm.oom.StackOOM.stackLeak(StackOOM.java:15)
10、方法区与常量池溢出
方法区存放的类信息,通过CGLib动态生成Class,在Class信息到达最大的容量限制后就会产生内存溢出异常。参数控制:
JDK1.7:-XX:PermSize=10m -XX:MaxPermSize=10m -XX:+PrintGCDetails
JDK1.8:-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m -XX:+PrintGCDetails
package com.xusg.study.jvm.oom; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * * @Author Xusg * @Date 18/2/7 16:37 */ public class MetaSpaceOOM { public static void main(String[] args) { int total = 0; while (true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(MetaSpaceOOM.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return methodProxy.invokeSuper(o, objects); } }); enhancer.create(); System.out.println("代理对象数:" + (++total)); } } }
Exception in thread "main" Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345) 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 com.xusg.study.jvm.oom.MetaSpaceOOM.main(MetaSpaceOOM.java:32)
相关文章推荐
- jvm学习记录 -- Java内存区域与内存溢出异常
- Java内存区域与内存溢出异常(JVM学习系列1)
- JVM高级特性与实践(一):Java内存区域 与 内存溢出异常
- java内存区域与内存异常(jvm学习)
- Java虚拟机学习之Java内存区域与内存溢出异常
- JVM 学习笔记1 JAVA内存区域与溢出异常
- JVM(一):Java内存区域与内存溢出异常
- 深入理解JVM之Java内存区域与内存溢出异常
- (JVM1)Java内存区域与内存溢出异常
- JVM--Java内存区域与内存溢出异常
- 学习JVM之java内存区域与异常
- JVM开篇---Java内存区域与内存溢出异常
- JVM-自动内存管理机制之Java内存区域与内存溢出异常
- 深入理解JVM(一)--Java内存区域与内存溢出异常
- 【JVM】Java内存区域与内存溢出异常
- JVM之Java内存区域与内存溢出异常
- 深入理解Java虚拟机JVM高级特性与最佳实践阅读总结——第二章 Java内存区域与内存溢出异常
- JVM学习-java内存区域与异常
- 深入理解JVM——java内存区域与内存溢出异常
- Java虚拟机学习笔记(一)——Java内存区域及内存溢出异常