• 深入理解Java虚拟机-第三版-第二章JVM 实践 StackOverFlowError OutOfMemoryError


      JVM一些参数
      -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8

      作者使用了一些参数来限制JVM的各部分的大小,以快速达到测试目的。这里我想说的是,很多同学说没有条件,工作中没有遇到高并发的场景,其实可以自己搭建一个受限JVM+JMeter+其它必要中间件(如MySQL,Redis等)组合来实现这个目的。

    ———————————————————————————————
    Java堆溢出
      通过设置-XX: +HeapDumpOnOutOf-MemoryError 可以让JVM在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后分析。
      解决思路:
      通过内存映像分析工具对Dump出来的堆转储快照信息进行分析。先确认导致OOM的对象,分清楚到底是Memory Leak还是Memory Overflow。如果是内存泄漏,可进一步通过工具查看泄露对象到GC Roots的引用链,找到泄露对象是通过怎样的路径、与哪些GC Roots相关联才导致垃圾收集器无法回收他们,进而分析内存泄漏代码的具体位置。

    public class HeapOOEMTest {
        static class OOEM {
        }
    
        public static void main(String[] args) {
            List<OOEM> ooemTest = new ArrayList<>();
            while (true) {
                ooemTest.add(new OOEM());
            }
        }
    }

    ———————————————————————————————
    Java栈溢出
      1.栈深度大于虚拟机所允许的最大深度,将抛出StackOverFlowError
      2.如果虚拟机栈内存允许动态扩展,当扩展容量无法申请到足够内存时,抛出OOME
      通过设置-Xss128K的方式设置JVM的栈容量可以比较方便地模拟该状态。不同的操作系统和不同版本的JVM栈容量会有所不同,主要取决于OS的内存分页大小限制。
      如果-Xss设置的过小,一些JVM启动时会报错。而在IDEA中,这样的设置可能不会生效。

      无论栈帧太大,还是栈容量太小,当新的栈帧内存无法分配时,HotSpot抛出的都是SOFE
      如果是建立过多线程导致的内存溢出,在不能减少线程数量或者更换64位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程。这种通过“减少内存”的手段来解决内存溢出的方式,如果没有这方面处理经验,一般比较难以想到,这一点读者需要在开发32位系统的多线程应用时注意。

    public class StackSOFETest {
        private int stackLength = 1;
    
        public void stackLeak() {
            stackLength++;
            stackLeak();
        }
    
        public static void main(String[] args) {
            StackSOFETest stackSOFETest = new StackSOFETest();
            try {
                stackSOFETest.stackLeak();
            } catch (Throwable e) {
                System.out.println("stack length:" + stackSOFETest.stackLength);
                throw e;
            }
        }
    }

    ———————————————————————————————
    方法区和运行时常量池溢出
      在JDK 6或更早之前的HotSpot虚拟机中,常量池都是分配在永久代中,我们可以通过-XX:PermSize和-XX:MaxPermSize限制永久代的大小,即可间接限制其中常量池的容量。

    public class MethodAreaOOEMTest {
        public static void main(String[] args) {
            Set<String> set = new HashSet<>();
            int i = 0;
            while (true) {
                set.add(String.valueOf(i++).intern());
            }
        }
    }

      在JDK8或者更高版本的JDK结果不同,如果设置了这两个参数,JVM还会给出提示:

    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=6M; support was removed in 8.0
    Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=6M; support was removed in 8.0

      String::intern()是一个本地方法,它的作用是如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用;否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

      在JDK 8以后,永久代便完全退出了历史舞台,元空间作为其替代者登场。
    HotSpot还是提供了一些参数作为元空间的防御措施,避免因运行时生成大量的动态类而造成的破坏性结果(JDK1.7之前表现为PermGen space OOME)
      -XX:MaxMetaspaceSize:设置元空间最大值,默认是-1,即不限制,或者说只受限于本地内存大小。
      -XX:MetaspaceSize:指定元空间的初始空间大小,以字节为单位,达到该值就会触发垃圾收集进行类型卸载,同时收集器会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过-XX:MaxMetaspaceSize(如果设置了的话)的情况下,适当提高该值。(动态的)
      -XX:MinMetaspaceFreeRatio:作用是在垃圾收集之后控制最小的元空间剩余容量的百分比,可减少因为元空间不足导致的垃圾收集的频率。类似的还有-XX:Max-MetaspaceFreeRatio,用于控制最大的元空间剩余容量的百分比。
    ———————————————————————————————
    直接内存溢出
      直接内存(Direct Memory)的容量大小可通过-XX:MaxDirectMemorySize参数来指定,如果不去指定,则默认与Java堆最大值(由-Xmx指定)一致。
      思路:由直接内存导致的内存溢出,一个明显的特征是在Heap Dump文件中不会看见有什么明显的异常情况,如果读者发现内存溢出之后产生的Dump文件很小,而程序中又直接或间接使用了DirectMemory(典型的间接使用就是NIO),那就可以考虑重点检查一下直接内存方面的原因了。

    public class DirectMemoryOOEMTest {
        public static void main(String[] args) throws IllegalAccessException {
            Field field = Unsafe.class.getDeclaredFields()[0];
            field.setAccessible(true);
            Unsafe unsafe = (Unsafe) field.get(null);
            while (true) {
                unsafe.allocateMemory(1024 * 1024);
            }
        }
    }

  • 相关阅读:
    HDU2502 月之数 组合数
    HDU1128 Self Numbers 筛选
    HDU2161 Primes
    HDU1224 Free DIY Tour 最长上升子序列
    HDU2816 I Love You Too
    winForm窗体设置不能随意拖动大小
    gridview 中SelectedIndexChanged 事件获得该行主键
    关于bin和obj文件夹。debug 和release的区别
    winform最小化时在任务栏里隐藏,且显示在托盘里
    wcf异常处理
  • 原文地址:https://www.cnblogs.com/bruceChan0018/p/15096613.html
Copyright © 2020-2023  润新知