做爲程序員,多多少少都會遇到一些內存溢出的場景,若是你還沒遇到,說明你工做的年限可能比較短,或者你根本就是個假程序員!哈哈,開個玩笑。今天,咱們就以Java代碼的方式來列舉幾個典型的內存溢出案例,但願你們在平常工做中,儘可能避免寫這些low水平的代碼。java
首先,咱們建立一個名稱爲BlowUpJVM的類,以後全部的案例實驗都是基於這個類進行。以下所示。程序員
public class BlowUpJVM { }
public static void testStackOverFlow(){ BlowUpJVM.testStackOverFlow(); }
棧不斷遞歸,並且沒有處理,因此虛擬機棧就不斷深刻不斷深刻,棧深度就這樣溢出了。編程
public static void testPergemOutOfMemory1(){ //方法一失敗 List<String> list = new ArrayList<String>(); while(true){ list.add(UUID.randomUUID().toString().intern()); } }
打算把String常量池堆滿,沒想到失敗了,JDK1.7後常量池放到了堆裏,也能進行垃圾回收了。windows
而後換種方式,使用cglib,用Class把老年代取堆滿微信
public static void testPergemOutOfMemory2(){ try { while (true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OOM.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } }); enhancer.create(); } } catch (Exception e){ e.printStackTrace(); } }
虛擬機成功內存溢出了,那JDK動態代理產生的類能不能溢出呢?併發
public static void testPergemOutOfMemory3(){ while(true){ final OOM oom = new OOM(); Proxy.newProxyInstance(oom.getClass().getClassLoader(), oom.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(oom, args); return result; } }); } }
事實代表,JDK動態代理差生的類不會形成內存溢出,緣由是:JDK動態代理產生的類信息,不會放到永久代中,而是放在堆中。app
public static void testNativeMethodOutOfMemory(){ int j = 0; while(true){ Printer.println(j++); ExecutorService executors = Executors.newFixedThreadPool(50); int i=0; while(i++<10){ executors.submit(new Runnable() { public void run() { } }); } } }
這個的原理就是不斷建立線程池,而每一個線程池都建立10個線程,這些線程池都是在本地方法區的,長此以往,本地方法區就溢出了。dom
public static void testStackOutOfMemory(){ while (true) { Thread thread = new Thread(new Runnable() { public void run() { while(true){ } } }); thread.start(); } }
線程的建立會直接在JVM棧中建立,可是本例子中,沒看到內存溢出,主機先掛了,不是JVM掛了,真的是主機掛了,不管在mac仍是在windows,都掛了。jvm
舒適提示,這個真的會死機的。ide
public static void testOutOfHeapMemory(){ List<StringBuffer> list = new ArrayList<StringBuffer>(); while(true){ StringBuffer B = new StringBuffer(); for(int i = 0 ; i < 10000 ; i++){ B.append(i); } list.add(B); } }
不斷往堆中塞新增的StringBuffer對象,堆滿了就直接溢出了。
public class BlowUpJVM { //棧深度溢出 public static void testStackOverFlow(){ BlowUpJVM.testStackOverFlow(); } //不能引發永久代溢出 public static void testPergemOutOfMemory1(){ //方法一失敗 List<String> list = new ArrayList<String>(); while(true){ list.add(UUID.randomUUID().toString().intern()); } } //永久代溢出 public static void testPergemOutOfMemory2(){ try { while (true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OOM.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } }); enhancer.create(); } } catch (Exception e){ e.printStackTrace(); } } //不會引發永久代溢出 public static void testPergemOutOfMemory3(){ while(true){ final OOM oom = new OOM(); Proxy.newProxyInstance(oom.getClass().getClassLoader(), oom.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(oom, args); return result; } }); } } //本地方法棧溢出 public static void testNativeMethodOutOfMemory(){ int j = 0; while(true){ Printer.println(j++); ExecutorService executors = Executors.newFixedThreadPool(50); int i=0; while(i++<10){ executors.submit(new Runnable() { public void run() { } }); } } } //JVM內存溢出 public static void testStackOutOfMemory(){ while (true) { Thread thread = new Thread(new Runnable() { public void run() { while(true){ } } }); thread.start(); } } //堆溢出 public static void testOutOfHeapMemory(){ List<StringBuffer> list = new ArrayList<StringBuffer>(); while(true){ StringBuffer B = new StringBuffer(); for(int i = 0 ; i < 10000 ; i++){ B.append(i); } list.add(B); } } }
若是以爲文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公衆號,跟冰河學習高併發編程技術。
最後,附上併發編程須要掌握的核心技能知識圖,祝你們在學習併發編程時,少走彎路。