中国建设网站齐齐哈尔市,直聘最新招聘信息,查询注册过的网站,企业网络的设计与实现JVM中常见的OOM#xff0c;那么如何通过自己编写代码产生这些OOM异常呢#xff1f;通过写代码重现异常#xff0c;是为了避免在工作中写出有OOM BUG的代码。之前虽然看过相关文章#xff0c;但是没自己写过这些代码#xff0c;这次在编写的实际过程中#xff0c;由于和书… JVM中常见的OOM那么如何通过自己编写代码产生这些OOM异常呢通过写代码重现异常是为了避免在工作中写出有OOM BUG的代码。之前虽然看过相关文章但是没自己写过这些代码这次在编写的实际过程中由于和书本使用的JDK版本不一致也会有点问题。其中印象最深刻的就是从JDK1.7开始常量池就已经不放在方法区了而是改到了Java堆中所以《深入理解JAVA虚拟机》中的有些知识也需要更新了。下面的代码基于JDK1.7来的。并且在运行程序的时候需要设置JVM参数如果不设置轻则需要等待很长时间才会出现异常重则系统假死甚至导致系统内存溢出。 在测试直接内存的时候引用了rt.jar中的sun.misc.Unsafe类如果使用了Eclipse作为IDE需要修改windows--preferences--java--compiler--Errors/Warinings选择Deprecated and restricted API将Forbidden reference(access rules)修改成ignore。 1 package org.zsl.learn.oom;2 3 import java.lang.reflect.Field;4 import java.lang.reflect.Method;5 import java.util.ArrayList;6 import java.util.List;7 8 9 import net.sf.cglib.proxy.Enhancer;10 import net.sf.cglib.proxy.MethodInterceptor;11 import net.sf.cglib.proxy.MethodProxy;12 import sun.misc.Unsafe;13 14 /**15 * 测试在代码中如何产生堆内存溢出、栈溢出超出长度、栈内存溢出栈不能扩展的情况下OOM、方法区内存溢出、常量池内存溢出16 * JDK1.717 * author Administrator18 *19 */20 public class TestOOM {21 private static int count 1;22 private static final int _1MB 1024*1024;23 24 ListString list new ArrayListString();25 26 //一个普通的对象27 static class OOMObjectClass{28 public OOMObjectClass(){}29 }30 31 /**32 * 通过list对象保持对对象列表的引用不然GC收集对象然后不断地向列表中添加新的对象就会发生OOM33 * 34 * VM args:-verbose:gc -Xms10M -Xmx10M -XX:PrintGCDetails -XX:SurvivorRatio8 -XX:HeapDumpOnOutOfMemoryError35 */36 public void testHeapOOM(){37 ListOOMObjectClass list new ArrayList();38 while(true){39 list.add(new OOMObjectClass());40 }41 }42 43 /**44 * 通过递归调用方法从而让方法栈产生栈 StackOverflowError45 * 46 * VM args:-verbose:gc -Xss128k47 */48 public void stackLeak(){49 count;50 stackLeak();51 }52 53 54 /**55 * 除了上述的递归调用可以产生溢出外还有就是过多的线程当栈内存无法动弹扩展是会出现OOM56 * 57 * 由于在Window的JVM中Jave的线程是映射到了操作系统的内核线程上故而这段代码的运行时非常危险的58 * 笔者运行的时候限制了JVM内存大小但是栈内存可以动态扩展所以电脑内存直接到了90%以上我果断停止了程序的运行59 * 由于栈内存只由-Xss参数控制并没有办法让其不自动扩展所以这段代码非常危险60 * 参数-verbose:gc -Xms10M -Xmx10M -Xss2M61 */62 public void stackLeakByThread(){63 while(true){64 Thread t new Thread(new Runnable() {65 66 Override67 public void run() {68 while (true){69 70 }71 }72 });73 t.start();74 count;75 }76 }77 78 /**79 * 常量池是存在于方法区内的故而只要限制了方法区的大小当不断新增常量的时候就会发生常量池的溢出80 * 81 * 笔者使用的是JDK1.7 64位此时的常量池已经不存在与方法区中而是迁移到了堆中故而测试的时候需要限制JVM的堆大小且不能自动扩展82 * VM args: -Xms10M -Xmx10M83 */84 public void constantPoolOOM(){85 int i0;86 while(true){87 list.add(String.valueOf(i).intern()); //String类型的intern方法是将字符串的值放到常量池中88 }89 }90 91 /**92 * 方法区是存放一些类的信息等所以我们可以使用类加载无限循环加载class这样就会出现方法区的OOM异常93 * 主要使用内部类的时候需要要使用静态内部类如果使用的是非静态内部类将不会发生方法区OOM94 * 使用了CGLib直接操作字节码运行时生成了大量的动态类95 * 需要者两个jar包cglib-2.2.2.jar asm-3.1.jar96 * VM args:-XX:PermSize10M -XX:MaxPermSize10M97 */98 public void methodAreaOOM(){99 while(true){
100 Enhancer eh new Enhancer();
101 eh.setSuperclass(OOMObjectClass.class);
102 eh.setUseCache(false);
103 eh.setCallback(new MethodInterceptor() {
104 Override
105 public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
106 return arg3.invokeSuper(arg0, arg2);
107 }
108 });
109 eh.create();
110 }
111 }
112
113 /**
114 * 要讨论这部分的内存溢出首先必须要说一下什么是直接内存
115 * 直接内存并不是JVM运行时数据区的一部分也不是JVM规范中定义的内存区域但是这部分内存也被频繁的使用也会产生OOM。
116 * JDK1.4中新加入了NIO类引入了一种Channel与Buffer的I/O方式它可以使用Native函数库直接分配堆外内存然后通过一个存储在JAVA堆里面的DirectByteBuffer对象作为
117 * 这些堆外内存的引用进而操作这样在某些场景中可以显著的提高性能避免了在native堆和java堆中来回复制数据。这这部分堆外内存就是直接内存了。
118 *
119 * 直接内存虽然不会受到JAVA堆大小的限制但是还是会受到本机内存大小的限制故而服务器管理员在设置JVM内存管理参数的时候如果忘记了直接内存那么当程序进行动态扩展的时候就有可能发生OOM
120 * 直接内存的容量可以通过-XXMaxDirectMemorySize指定如果不指定那么默认与JAVA堆得最大值一样。
121 *
122 * VM args:-Xmx20M -XX:MaxDirectMemorySize10M
123 * throws SecurityException
124 * throws NoSuchFieldException
125 * throws IllegalAccessException
126 * throws IllegalArgumentException
127 */
128 public void directMemoryOOM() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
129 Field unsafeField Unsafe.class.getDeclaredField(theUnsafe);
130 unsafeField.setAccessible(true);
131 Unsafe unsafe (Unsafe)unsafeField.get(null);
132 while(true){
133 unsafe.allocateMemory(_1MB);
134 }
135 }
136
137
138
139
140 public static void main(String[] args) {
141 TestOOM oom new TestOOM();
142 // ---------测试堆内存溢出-----------
143 // oom.testHeapOOM();
144
145 // ---------测试栈溢出----------
146 // try{
147 // oom.stackLeak();
148 // }catch(Throwable error){
149 // System.out.println(Stack length--count);
150 // throw error;
151 // }
152
153 // ---------测试由于栈动态扩展导致的OOM----------
154 // try{
155 // oom.stackLeakByThread();
156 // }catch(Throwable error){
157 // System.out.println(Stack length--count);
158 // throw error;
159 // }
160
161 // ----------测试方法区溢出----------
162 // oom.methodAreaOOM();
163
164 // ----------测试常量池溢出----------
165 // oom.constantPoolOOM();
166
167 // ----------测试直接内存溢出----------
168
169 try {
170 oom.directMemoryOOM();
171 } catch (Exception e) {
172 System.out.println(e);
173 }
174
175
176
177 }
178
179
180 } 转载于:https://www.cnblogs.com/printN/p/6901668.html