图解JVM内存结构及内存/栈溢出原因解析 我不是女神ヾ 2022-06-09 10:45 161阅读 0赞 # 一、背景知识 # ## 1、JVM体系结构 ## ![Center][] ## 2、JVM运行时数据区 ## ![Center 1][] ## 3、JVM内存模型 ## ### JVM运行时内存 = 共享内存区 + 线程内存区 ### ![Center 2][] ## 3-1、共享内存区 ## 共享内存区 = 持久带 + 堆 持久带 = 方法区 + 其他 堆 = Old Space + Young Space Young Space = Eden + S0 + S1 ![Center 3][] ## 3-1-1、持久代 ## JVM用持久带(Permanent Space)实现方法区,主要存放所有已加载的类信息,方法信息,常量池等等。 可通过-XX:PermSize和-XX:MaxPermSize来指定持久带初始化值和最大值。 Permanent Space并不等同于方法区,只不过是Hotspot JVM用Permanent Space来实现方法区而已,有些虚拟机没 有Permanent Space而用其他机制来实现方法区。 ## 3-1-2、堆 ## 堆(heap),主要用来存放类的对象实例信息(包括new操作实例化的对象和定义的数组)。 堆分为Old Space(又名,Tenured Generation)和Young Space。 Old Space主要存放应用程序中生命周期长的存活对象; Eden(伊甸园)主要存放新生的对象; S0和S1是两个大小相同的内存区域,主要存放每次垃圾回收后Eden存活的对象,作为对象从Eden过渡到Old Space 的缓冲地带(S是指英文单词Survivor Space)。 堆之所以要划分区间,是为了方便对象创建和垃圾回收,后面垃圾回收部分会解释。 ## 3-2、线程内存区 ## 线程内存区=单个线程内存+单个线程内存+....... 单个线程内存=PC Regster+JVM栈+本地方法栈 JVM栈=栈帧+栈帧+..... 栈帧=局域变量区+操作数区+帧数据区 ![Center 4][] 在Java中,一个线程会对应一个JVM栈(JVM Stack),JVM栈里记录了线程的运行状态。 JVM栈以栈帧为单位组成,一个栈帧代表一个方法调用。栈帧由三部分组成:局部变量区、操作数栈、帧数据区。 # 二、堆溢出 # 堆(Heap)是Java存放对象实例的地方。 堆溢出可以分为以下两种情况,这两种情况都会抛出OutOfMemoryError:java heap space异常: ## 1、内存泄漏 ## 内存泄漏是指对象实例在新建和使用完毕后,仍然被引用,没能被垃圾回收释放,一直积累,直到没有剩余 内存可用。 如果内存泄露,我们要找出泄露的对象是怎么被GC ROOT引用起来,然后通过引用链来具体分析泄露的原因。 分析内存泄漏的工具有:Jprofiler,visualvm等。 示例代码: **\[java\]** [ view plain][view plain] [ copy][view plain] [ print][view plain] [?][view plain] 1. package com.jvm; 2. 3. import java.util.ArrayList; 4. import java.util.List; 5. import java.util.UUID; 6. 7. /\*\* 8. \* 内存泄漏 9. \* @author feizi 10. \* @time 2015-1-23上午8:42:53 11. \*/ 12. public class OOMTest \{ 13. 14. public static void main(String\[\] args) \{ 15. 16. List<UUID> list = new ArrayList<UUID>(); 17. while(true)\{ 18. list.add(UUID.randomUUID()); 19. \} 20. \} 21. 22. \} package com.jvm; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * 内存泄漏 * @author feizi * @time 2015-1-23上午8:42:53 */ public class OOMTest { public static void main(String[] args) { List<UUID> list = new ArrayList<UUID>(); while(true){ list.add(UUID.randomUUID()); } } } 看看控制台的输出结果,因为我这边的JVM设置的参数内存足够大,所以需要等待一定的时间,才能看到效果: ![Center 5][] 如果是用CMD命令行,就可以自己指定参数编译运行了,这样效果就更快一些: 通过下列命令运行程序,注意先要用javac命令将.java源文件编译成.class类字节码文件。 **\[java\]** [ view plain][view plain] [ copy][view plain] [ print][view plain] [?][view plain] 1. java -Xms10M -Xmx10M -XX:-UseGCOverheadLimit OOMTest java -Xms10M -Xmx10M -XX:-UseGCOverheadLimit OOMTest ![Center 6][] ## 2、内存溢出 ## 内存溢出是指当我们新建一个实力对象时,实例对象所需占用的内存空间大于堆的可用空间。 如果出现了内存溢出问题,这往往是程序本生需要的内存大于了我们给虚拟机配置的内存,这种情况下,我们可以采用调大-Xmx来解决这种问题。 示例代码: **\[java\]** [ view plain][view plain] [ copy][view plain] [ print][view plain] [?][view plain] 1. package com.jvm; 2. 3. import java.util.ArrayList; 4. import java.util.List; 5. 6. /\*\* 7. \* 内存溢出 8. \* @author feizi 9. \* @time 2015-1-23上午8:56:22 10. \*/ 11. public class OOMTest\_1 \{ 12. public static void main(String args\[\])\{ 13. List<byte\[\]> byteList = new ArrayList<byte\[\]>(); 14. byteList.add(new byte\[1000 \* 1024 \* 1024\]); 15. \} 16. \} package com.jvm; import java.util.ArrayList; import java.util.List; /** * 内存溢出 * @author feizi * @time 2015-1-23上午8:56:22 */ public class OOMTest_1 { public static void main(String args[]){ List<byte[]> byteList = new ArrayList<byte[]>(); byteList.add(new byte[1000 * 1024 * 1024]); } } 看看控制台的运行效果: ![Center 7][] 使用CMD命令行指定参数运行: **\[java\]** [ view plain][view plain] [ copy][view plain] [ print][view plain] [?][view plain] 1. java -verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC OOMTest\_1 java -verbose:gc -Xmn10M -Xms20M -Xmx20M -XX:+PrintGC OOMTest_1 ![Center 8][] # 三、线程栈 # 栈(JVM Stack)存放主要是栈帧( 局部变量表, 操作数栈 , 动态链接 , 方法出口信息 )的地方。注意区分栈和栈帧:栈里包含栈帧。 与线程栈相关的内存异常有两个: a)、StackOverflowError(方法调用层次太深,内存不够新建栈帧) b)、OutOfMemoryError(线程太多,内存不够新建线程) ## 1、java.lang.StackOverflowError ## 栈溢出抛出java.lang.StackOverflowError错误,出现此种情况是因为方法运行的时候,请求新建栈帧时, 栈所剩空间小于战帧所需空间。 例如,通过递归调用方法,不停的产生栈帧,一直把栈空间堆满,直到抛出异常 : 示例代码: **\[java\]** [ view plain][view plain] [ copy][view plain] [ print][view plain] [?][view plain] 1. package com.jvm; 2. /\*\* 3. \* 栈溢出 4. \* @author feizi 5. \* @time 2015-1-23上午9:13:11 6. \*/ 7. public class SOFTest \{ 8. 9. public void stackOverFlowMethod()\{ 10. stackOverFlowMethod(); 11. \} 12. 13. /\*\* 14. \* 通过递归调用方法,不停的产生栈帧,一直把栈空间堆满,直到抛出异常 : 15. \* @param args 16. \*/ 17. public static void main(String\[\] args) \{ 18. SOFTest sof = new SOFTest(); 19. sof.stackOverFlowMethod(); 20. \} 21. 22. \} package com.jvm; /** * 栈溢出 * @author feizi * @time 2015-1-23上午9:13:11 */ public class SOFTest { public void stackOverFlowMethod(){ stackOverFlowMethod(); } /** * 通过递归调用方法,不停的产生栈帧,一直把栈空间堆满,直到抛出异常 : * @param args */ public static void main(String[] args) { SOFTest sof = new SOFTest(); sof.stackOverFlowMethod(); } } 看看控制台运行的效果: ![Center 9][] [Center]: /images/20220609/970def15bcb64d2189a53fb58105c5c0.png [Center 1]: /images/20220609/fcdfd6cdac7443dab595464ac4d93e58.png [Center 2]: /images/20220609/5241ac938033440892b94defcc792c7a.png [Center 3]: /images/20220609/27537c17463945329d8818b0a28468bb.png [Center 4]: /images/20220609/9b832a9d7f3b416598de6df5e68d3a2c.png [view plain]: http://blog.csdn.net/z69183787/article/details/75530650# [Center 5]: /images/20220609/5e641e9dc1154670be532d2cd32516da.png [Center 6]: /images/20220609/0b01befc772640d78efc70053ce6391d.png [Center 7]: /images/20220609/207029468d6b4300abdf41c0f5fe9206.png [Center 8]: /images/20220609/7b424a5a4c35477087f71a41393b4532.png [Center 9]: /images/20220609/d748cd4e7c904e689cbde8d04a4146bc.png
相关 Java内存溢出问题解析 Java内存溢出,简单来说就是程序在运行过程中消耗的内存超过了系统的可分配的最大内存容量,导致系统崩溃。 内存溢出的主要原因包括: 1. 对大对象或数组进行操作:未正确管理 「爱情、让人受尽委屈。」/ 2024年09月16日 06:03/ 0 赞/ 7 阅读
相关 Java内存溢出问题解析 在Java编程中,内存溢出(Out of Memory, OOM)是一种常见的运行时错误。以下是对Java内存溢出问题的解析: 1. **资源不足**:最常见的情况是系统可用 Dear 丶/ 2024年09月10日 04:30/ 0 赞/ 21 阅读
相关 图解JVM内存结构 下图所示: 1、左上方墨绿色区域(程序计数器、虚拟机栈、本地方法栈)为**线程私有**; 2、左侧中间及下方蓝色区域(堆区、方法区)为堆为**线程共享**,也是JVM... ﹏ヽ暗。殇╰゛Y/ 2024年04月18日 10:23/ 0 赞/ 20 阅读
相关 图解JVM内存结构 JVM内存结构大致如下: 其中白色块部分是线程共享,粉色块是线程隔离的 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_ 小鱼儿/ 2022年11月21日 03:59/ 0 赞/ 125 阅读
相关 图解JVM内存结构及内存/栈溢出原因解析 一、背景知识 1、JVM体系结构 ![Center][] 2、JVM运行时数据区 ![Center 1][] 我不是女神ヾ/ 2022年06月09日 10:45/ 0 赞/ 162 阅读
相关 java 内存溢出 栈溢出的原因 内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出。如果出现这种现象可行代码排查: 一)是否应用中的类中和引用变量过多使用了Static修饰 如p r囧r小猫/ 2022年03月14日 10:58/ 0 赞/ 391 阅读
相关 JVM - 程序模拟 堆内存溢出, 栈内存溢出, 永久代内存溢出 总结: 死循环 :堆内存溢出 递归 :栈内存溢出 Java虚拟机中描述了两种异常 1、如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOver 冷不防/ 2022年03月06日 09:26/ 0 赞/ 366 阅读
相关 jvm 内存溢出-直接内存溢出 jvm 内存溢出-直接内存溢出 DirectMemory 容量可通过 `-XX:MaxDirectMemorySize` 指定,如果不指定,则默认与 Java 堆最大值( 雨点打透心脏的1/2处/ 2022年03月01日 03:38/ 0 赞/ 372 阅读
还没有评论,来说两句吧...