`

JVM内存溢出的测试

    博客分类:
  • JVM
 
阅读更多
    本人初学java,看到面试官问道JVM的问题蛮多,就学了一点点,拿出来和大家分享,有什么错误的地方,希望大家指出来。
    要解决内存溢出的问题,我们说为什么内存溢出。运行一个大型的软件或游戏,所需要的内存空间远远超过了,你主机内安装的内存所承受的大小,就叫内存溢出。
    对于虚拟机而言,JVM包括一组寄存器,一个栈,一个垃圾回收堆一个存储方法域。我们的实例对象会放在java堆空间,普通对象存放在栈中,以及方法区,常量池等等,还有本机内存,所以对于内存溢出的问题,我们已经有眉目从哪些地方找到元凶了。
A:java堆溢出
java堆用于存放我们的实例对象,当我们不断的创建对象,并一直持有对象的引用,防止被gc。
测试如下:
[img]package demo;

import java.util.ArrayList;
import java.util.List;

/**
* VM Args:-verbose:gc -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
* */
public class HeapOverFlow {
public static void main(String[] args) {
List<HeapOverFlow> hofs=new ArrayList<HeapOverFlow>();
while(true){
hofs.add(new HeapOverFlow());
}
}
}
[/img]

设置xms为20m,xmx为20m,执行效果如下:

[img]
[GC 17190K->17190K(20352K), 0.0071101 secs]
[GC 18470K->18469K(20352K), 0.0078375 secs]
[GC 18573K->18558K(20352K), 0.0011519 secs]
[Full GC 18558K->18558K(20352K), 0.0546033 secs]
[Full GC 18558K->17808K(20352K), 0.0763401 secs]
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid4784.hprof ...
Heap dump file created [32577359 bytes in 0.842 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2760)
at java.util.Arrays.copyOf(Arrays.java:2734)
at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
at java.util.ArrayList.add(ArrayList.java:351)
at demo.HeapOverFlow.main(HeapOverFlow.java:13)

[/img]
发生这种情况具体还要看是内存泄露还是内存溢出。如果存在内存泄露就要找到泄露点,如果是内存溢出,则需要增加内存空间。至于怎么做,目前还没研究哈。

B:虚拟机栈和本地方法栈溢出

由于在HotSpot虚拟机中并不区分虚拟机栈和本地方法区栈,因此对于HotSpot来说,-Xoss(设置本地方法栈大小)参数是无效的,栈容量由-Xss参数设定。关于虚拟机栈和本地方法区栈,在Java虚拟机规范中描述了两种异常:
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

《深入浅出java虚拟机》这本书中谈到单线程的场景下只能浮现StackOverflowError,那我们就先来看看单线程场景下到底会是什么样子。

[img]public class StackOverFlow {
private int stackLength = 1;
  private void stackLeak() {
    stackLength++;
    stackLeak();
  }
 
  public static void main(String[] args) throws Throwable {
  StackOverFlow oom = new StackOverFlow();
    try {
      oom.stackLeak();
    } catch (Throwable e) {
      System.out.println("stack length:" + oom.stackLength);
      throw e;
    }
  }
  }[/img]
设置-Xss128k 运行结果如下:

[img]stack length:2402
Exception in thread "main" java.lang.StackOverflowError
at demo.StackOverFlow.stackLeak(StackOverFlow.java:11)
at demo.StackOverFlow.stackLeak(StackOverFlow.java:12)[/img]

通过不断创建线程耗尽内存也可以呈现出OutOfMemoryError异常,由于在windows下会造成死机,这里我就不试了。

C:运行时常量池溢出

向运行时常量池中添加内容最简单的方式就是使用String.intern()方法。由于常量池分配在方法区内,可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量。

例子:
import java.util.ArrayList;
import java.util.List;

/**
* VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
* @author Administrator
*
*/
public class StaticConstantPoolOF {
public static void main(String[] args) {

      List<String> list = new ArrayList<String>();

      int i = 0;

      while (true) {
        list.add(String.valueOf(i++).intern());
      }
    }
}

运行结果如下:
[img][GC 3159K->2263K(5056K), 0.0005486 secs]
[Full GC 2403K->1018K(5056K), 0.0387303 secs]
[Full GC 1018K->1018K(5056K), 0.0416562 secs]
[Full GC 1033K->242K(5056K), 0.0150953 secs]
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at demo.StaticConstantPoolOF.main(StaticConstantPoolOF.java:24)[/img]

D:方法区溢出

方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。测试这个区域只要在运行时产生大量的类填满方法区,知道溢出。《深入理解Java虚拟机》借助CGlib直接操作字节码运行时,生成了大量的动态类。

当前主流的Spring和Hibernate对类进行增强时,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的Class可以加载到内存。
[img]import net.sf.cglib.proxy.Enhancer;
  import net.sf.cglib.proxy.MethodInterceptor;
  import net.sf.cglib.proxy.MethodProxy;

  /**
   * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
   *
   */
  public class JavaMethodAreaOOM {
    public static void main(String[] args) {
      while (true) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(OOMObject.class);
        enhancer.setUseCache(false);
        enhancer.setCallback(new MethodInterceptor() {
          public Object intercept(Object object, Method method,
              Object[] args, MethodProxy proxy) throws Throwable{
            return proxy.invokeSuper(object, args);
          }
        });
        enhancer.create();
      }

    }

    static class OOMObject {

    }

  }[/img]

工程中要引入cglib-2.2.2.jar和asm-all-3.3.jar。
方法区的内存溢出问题同样存在jdk6和jdk7版本之间的区别,同运行时常量池内存溢出。
方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收掉,判定条件是非常苛刻的。在经常动态生成大量Class的应用中,需要特别注意类的回收状况。这类场景除了上面提到的程序使用了CGLib字节码增强外,常见的还有:大量JSP或动态生成JSP文件的应用、基于OSGi的应用等。

E:本机直接内存溢出

DirectMemory容量可以通过-XX:MaxDirectMemorySize指定。

  import java.lang.reflect.Field;
  import sun.misc.Unsafe;

  /**
   * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M
   *
   */
  public class DirectMemoryOOM {

    private static final int _1MB = 1024 * 1024;

    /**
     * @param args
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     */
    public static void main(String[] args) throws IllegalArgumentException,
        IllegalAccessException {
      // TODO Auto-generated method stub
      Field unsafeField = Unsafe.class.getDeclaredFields()[0];
      unsafeField.setAccessible(true);
      Unsafe unsafe = (Unsafe) unsafeField.get(null);
     
      while(true){
        unsafe.allocateMemory(_1MB);
      }
    }

  }
该例子还没测试。
分享到:
评论

相关推荐

    关于tomcat乱码以及tomcat jvm 内存溢出问题的解决方案和理论

    标题中的“关于tomcat乱码以及...综上所述,解决Tomcat的乱码问题需要正确配置字符编码,而处理JVM内存溢出则需优化内存分配和垃圾收集策略。对于MySQL的配置,理解`my.cnf`文件的内容对于数据库的高效运行也至关重要。

    JVM实战-对象访问与内存溢出异常解析

    6. **了解本机直接内存溢出异常的测试**:通过使用`sun.misc.Unsafe`类操作非堆内存,探索如何触发直接内存溢出异常。 #### 实验实现过程 ##### Java堆内存溢出异常的测试 为了测试Java堆内存溢出异常,通常会...

    JRockit JAVA内存溢出检测的使用(CHM)

    **JRockit JAVA内存溢出检测的使用** Java内存溢出是开发和运行Java应用程序时常见的问题,可能导致程序崩溃或性能急剧下降。JRockit JVM(Java Virtual Machine)由Oracle公司开发,它提供了强大的内存管理和分析...

    Python内存泄漏和内存溢出的解决方案

    虽然Python有内置的垃圾回收机制,但仍然可能出现内存泄漏和内存溢出的问题,影响程序的稳定性和效率。 **一、Python内存泄漏** 内存泄漏通常是由于以下几个原因引起的: 1. **C扩展模块的内存泄漏**:使用C语言...

    解决jetty8内存溢出版本

    综上所述,解决Jetty 8内存溢出问题需要综合考虑JVM参数配置、代码优化、资源管理策略以及监控与分析等多个层面。通过对上述知识点的理解和实践,可以有效地预防和解决Jetty 8的内存溢出问题,提高服务的稳定性和...

    基于HeapAnalyzer456.jar 分析java内存溢出

    1. **生成堆转储文件(Heap Dump)**:当Java应用程序出现内存溢出异常时,可以通过JVM参数设置(如`-XX:+HeapDumpOnOutOfMemoryError`)让JVM自动生成堆转储文件,或者通过`jmap`命令手动生成。堆转储文件是分析...

    java 内存溢出分析工具 HeapAnalyzer

    Java内存溢出(Out of Memory,OOM)是Java应用程序中常见的问题,会导致程序崩溃或性能急剧下降。HeapAnalyzer是一款强大的工具,专为分析Java应用程序的内存状况,特别是针对内存溢出问题进行诊断。本文将详细介绍...

    jvm内存分析工具mat安装包

    MAT,全称Memory Analyzer Tool,是IBM开发的一款强大的JVM内存分析工具,尤其适用于诊断Java应用程序的内存泄漏问题。在Java开发过程中,内存溢出(Out Of Memory)问题常常会导致程序异常终止,而MAT就是解决这类...

    解决OutOfMemoryError内存溢出

    ### 解决OutOfMemoryError内存溢出 在Java开发过程中,我们经常会遇到`java.lang.OutOfMemoryError`(简称OOM)的问题。这个问题的发生主要是由于JVM内存不足或程序中存在内存泄漏所引起的。本文将深入探讨OOM产生...

    jprofiler的使用及联调内存溢出解决方案交流

    jprofiler的使用及联调内存溢出解决方案交流 jprofiler 是一个全功能的 Java 剖析工具,专用于分析 J2SE 和 J2EE 应用程序。它把 CPU、执行绪和内存的剖析组合在一个强大的应用中,提供许多 IDE 整合和应用服务器...

    JAVA内存溢出详解.doc

    Java内存溢出(Out Of Memory,OOM)是Java应用程序运行时常见的问题,它通常发生在程序对内存需求超过了Java虚拟机(JVM)所能提供的可用内存时。本文将深入探讨Java内存溢出的原因、表现以及如何解决。 1. **Java...

    TOMCAT内存溢出之解决方法

    Tomcat内存溢出是由于JVM的虚拟内存默认为128M,当超过这个值时就把先前占用的内存释放,而导致出现HTTP500的错误。当用户执行一个大数据的应用时,系统会提示出错,前台错误为:HTTP Status 500-Dispatch[EAITool] ...

    java内存泄露、溢出检查方法和工具

    解决内存溢出问题通常需要调整JVM的内存参数,如`-Xms`和`-Xmx`用于设置堆的初始大小和最大大小,以及`-XX:MaxPermSize`(对于较旧的JVM版本)或`-XX:MaxMetaspaceSize`(对于Java 8及以上版本)来控制方法区的大小...

    JVM 内存管理及调优.zip_JVM内存_java_memory

    - **Metaspace大小**:监控和调整元空间大小,防止因类加载过多导致的内存溢出。 - **对象创建优化**:减少不必要的对象创建,复用对象,避免短生命周期对象进入老年代。 - **内存泄漏检测**:使用工具检测潜在的...

    JVM内存参数调优

    ### JVM内存参数调优 在Java开发过程中,合理地配置JVM(Java虚拟机)的内存参数对于提高程序运行效率、避免内存溢出等问题至关重要。本文将深入探讨JVM内存参数调优的相关知识点,帮助开发者更好地理解并掌握如何...

    解决Java程序内存溢出的办法

    在Java编程中,内存溢出(Out...总之,解决Java程序内存溢出问题需要深入理解内存管理、JVM参数、垃圾回收以及代码优化等多个方面。通过不断学习和实践,开发者可以有效地预防和解决这类问题,确保程序的稳定性和性能。

    java excel导出tomcat内存溢出处理方法

    在MyEclipse中,可以通过修改`myeclipse.ini`文件来调整JVM参数,从而避免内存溢出问题的发生。具体步骤如下: 1. 打开MyEclipse安装目录下的`myeclipse.ini`文件(例如:`G:\MyEclipse8.5\Genuitec\MyEclipse8.5\...

Global site tag (gtag.js) - Google Analytics