当前位置: 首页 > 科技观察

深入理解JVM的内存区和内存溢出

时间:2023-03-20 16:30:32 科技观察

文章目录1.Java内存区和内存溢出异常1.1。运行时数据区1.1.1。程序计数器1.1.2。Java虚拟机堆栈1.1.3。本地方法栈1.1.4。Java堆(JavaHeap)1.1.5。方法领域1.1.6。运行时常量池1.1.7。直接记忆1.2。HotSpot虚拟机1.2.1。对象创建1.2.2。对象访问位置1.3。OOM异常解决方案1.4.参考Java内存区和内存溢出异常运行时数据区程序计数器当前线程执行的字节码行号指示当前线程是私有的,不会出现OutOfMemoryError,生命周期与线程相同。java方法执行的内存模型。每个方法执行时都会创建一个栈帧来存放局部变量表(基本类型、对象引用)、操作数栈、动态链接、方法出口等信息。StackOverflowError异常:当线程请求的栈深度为大于虚拟机允许的深度OutOfMemoryError异常:如果扩展栈时无法申请到足够的内存,本地方法栈类似于虚拟机栈,主要服务于虚拟机使用的native方法。在HotSpot虚拟机中,本地方法栈和虚拟机栈直接组合在一起一个Java堆(JavaHeap)java堆是所有线程共享的一块内存区域。在虚拟机启动时创建这个区域的唯一目的是存储对象实例。java堆是垃圾收集器管理的主要区域。java堆还可以细分为:新生代和老年代。更详细的,有Eden空间,FormSurvivor空间,ToSurvivor空间等。堆的大小可以通过-Xmx和-Xms控制OutOfMemoryError异常:当堆中没有内存完成实例分配时,并且无法再扩展堆。方法区是线程间共享的,用于存放类信息、常量、静态变量、虚拟机已经加载的Just-in-time编译器编译后的代码等数据。OutOfMemoryError异常:当方法区不能满足内存分配要求时,运行时常量池方法区的一部分用于存放编译过程中产生的各种字面量和符号引用。OutOfMemoryError异常:当常量池不能再申请内存时,directmemoryNIO可以使用Native函数库直接分配堆外内存,堆中的DirectByteBuffer对象作为这块内存引用操作的大小为不受Java堆大小的限制,而是受本地机器(服务器)内存的限制。OutOfMemoryError异常:当系统内存不足时,创建一个HotSpot虚拟机对象,当虚拟机遇到新的指令时,会先检查该对象的参数是否定位到常量池中某个类的符号引用,并检查符号引用所表示的类是否已经加载、解析和初始化。如果没有,则必须先执行类加载过程。类加载检查通过后,虚拟机会为新生对象分配内存。对象需要的内存大小可以在类加载完成后确定。内存分配可以使用“指针冲突”和“空闲列表”的方法。对象访问定位Java程序需要通过引用栈上的数据来操作堆上的特定对象。访问方式有两种:句柄和直接指针。句柄访问java堆会划分一块内存作为句柄池,引用存放在对象的句柄地址中,句柄中包含对象实例数据和类型数据的具体地址信息直接指针访问的布局java堆对象需要考虑如何将访问类型数据的相关信息放在引用中。引用中存储的是对象地址。dump快照使用jmap产生dump文件,win通过任务管理器查看tomcat的进程pid,linux使用ps命令查看进程pid,然后使用jmap命令先使用内存映像分析工具(如Eclipse'sMemoryAnalyzer),常见的情况是:内存泄漏,对象死了,无法被垃圾收集器自动回收,通过找出泄漏代码的位置和原因来确定解决方案;内存溢出,内存中的对象肯定还活着,这说明Java堆分配空间不足,查看堆设置大小(-Xmx和-Xms),查看代码是否存在对象生命周期为太久或保持太久的状态。OOM异常示例:packageoom;importjava.util.ArrayList;importjava.util.List;/***VMArgs:-Xms20m-Xmx20m-XX:+HeapDumpOnOutOfMemoryError*@ClassName:HeapOOM**/publicclassHeapOOM{staticclassOOMObject{}publicstaticvoidmain(String[]args){Listlist=newArrayList();while(true){list.add(newOOMObject());}}}