今天看书的时候讲解了jvm几块内存区域的内存溢出情况,这里总结一下加深印象。
主要有两种内存溢出问题:1.outofmemory;2.stackoverflow。
四块内存区域:1.java堆溢出;2:虚拟机栈和本地方法栈溢出;3.方法区和运行时常量池溢出;4.直接内存溢出;
其中outmemory比较常见于java堆、方法区和运行时常量池、直接内存三块内存区域;stackoverflow常见于虚拟机栈和本地方法栈;特殊情况下outmemory也会出现在虚拟机栈和本地方法栈区域;
java堆溢出主要发生在创建对象时,当创建对象所需要的内存空间大于堆上所剩余内存时就会出现outofmemory异常;可以通过设置一个较小的堆内存,然后创建较多的对象来测试这种异常情况。通过jvm参数-Xms和-Xmx来设置jvm堆内存的大小。
虚拟机栈和本地方法栈可能会出现outofmemory和stackoverflow两种异常,当线程请求的栈深度大于虚拟机允许的最大深度就会产生stackoverflow异常。而当多个线程同时请求栈空间时,会产生outofmemory异常主要原因是多个线程请求栈空间时每个线程所能占有的内存是有限制的,而进程所能享有的内存也是有限的。线程多的情况下会导致进程所分配到的内存不够使用从到发生outofmemory异常。以上第一种情况可以通过递归调用来模拟,第二种则可以创建多个线程请求内存空间来模拟。对于栈空间可以通过jvm参数-Xss来设置。
方法区和运行时常量池主要是用来存储类的信息和一些常量。这一块区域主要会发生outofmemory异常。hotspot虚拟机上方法区主要是分配在永久代之上。可以通过动态加载类和动态的往常量池中添加数据来产生此异常。动态加载类主要是通过反射的方式来加载类。向常量池中添加数据可通过String.intern()方法来实现。此方法主要的作用时检查常量池中是否有此字符串,存在返回其引用,不存在则在常量池中创建此对象并返回其引用。(注:此方法在不同jdk版本中实现有所区别)
直接内存区主要是会产生outofmemory异常,主要是NIO使用,通过存在java堆中的directbytebuffer对象作为直接内存区域的引用来进行操作。可以通过设置jvm参数-XX:MaxDirectMemorySize来指定其大小,不设置则与java堆最大值相同。此块区域如果发生内存泄漏并不会在堆转储快照中出现,可以通过是否使用NIO来判定问题。我没有模拟此区域内存泄漏的情况