文档章节

Java堆,方法区,Java栈和本地方法栈浅析

思想永无止境
 思想永无止境
发布于 2016/11/04 11:56
字数 805
阅读 7
收藏 0

最近在看《深入理解Java虚拟机》,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构:

感觉有必要通过几个实在的例子来加深对这几个区域的了解

1)Java堆

所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示:

[java]  view plain copy
  1. public class HeapOOM {  
  2.       
  3.     static class OOMObject{}  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public static void main(String[] args) {  
  9.         List<OOMObject> list = new ArrayList<OOMObject>();  
  10.           
  11.         while(true){  
  12.             list.add(new OOMObject());  
  13.         }  
  14.     }  
  15.   
  16. }  

加上JVM参数-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,就能很快报出OOM:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

并且能自动生成Dump。

2)方法区

方法区是存放虚拟机加载类的相关信息,如类、静态变量和常量,大小由-XX:PermSize和-XX:MaxPermSize来调节,类太多有可能撑爆永久带:

[java]  view plain copy
  1. public class MethodAreaOOM {  
  2.       
  3.     static class OOMOjbect{}  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public static void main(String[] args) {  
  9.         // TODO Auto-generated method stub  
  10.         while(true){  
  11.             Enhancer eh = new Enhancer();  
  12.             eh.setSuperclass(OOMOjbect.class);  
  13.             eh.setUseCache(false);  
  14.             eh.setCallback(new MethodInterceptor(){  
  15.   
  16.                 @Override  
  17.                 public Object intercept(Object arg0, Method arg1,  
  18.                         Object[] arg2, MethodProxy arg3) throws Throwable {  
  19.                     // TODO Auto-generated method stub  
  20.                     return arg3.invokeSuper(arg0, arg2);  
  21.                 }  
  22.                   
  23.             });  
  24.             eh.create();  
  25.         }  
  26.     }  
  27.   
  28. }  

加上永久带的JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后会报如下异常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

静态变量或常量也会有可能撑爆方法区:

[java]  view plain copy
  1. public class ConstantOOM {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         // TODO Auto-generated method stub  
  8.         List<String> list = new ArrayList<String>();  
  9.         int i=0;  
  10.         while(true){  
  11.             list.add(String.valueOf(i++).intern());  
  12.         }  
  13.     }  
  14.   
  15. }  

同样加上JVM参数:-XX:PermSize=10M -XX:MaxPermSize=10M,运行后报如下异常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

3)Java栈和本地方法栈

栈是存放线程调用方法时存储局部变量表,操作,方法出口等与方法执行相关的信息,栈大小由Xss来调节,方法调用层次太多会撑爆这个区域,samples如下所示:

[java]  view plain copy
  1. package com.cutesource;  
  2.   
  3. public class StackOOM {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.       
  9.     private int stackLength = 1;  
  10.       
  11.     public void stackLeak(){  
  12.         stackLength++;  
  13.         stackLeak();  
  14.     }  
  15.       
  16.     public static void main(String[] args) throws Throwable{  
  17.         // TODO Auto-generated method stub  
  18.         StackOOM oom = new StackOOM();  
  19.         try{  
  20.             oom.stackLeak();  
  21.         }catch(Throwable err){  
  22.             System.out.println("Stack length:" + oom.stackLength);  
  23.             throw err;  
  24.         }  
  25.           
  26.     }  
  27.   
  28. }  

设置JVM参数:-Xss128k,报出异常:

Exception in thread "main" java.lang.StackOverflowError

打印出Stack length:1007,这里可以看出,在我的机器上128k的栈容量能承载深度为1007的方法调用。当然报这样的错很少见,一般只会出现无限循环的递归中,另外,线程太多也会占满栈区域:

[java]  view plain copy
  1. package com.cutesource;  
  2.   
  3. public class StackOOM {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.       
  9.     private int stackLength = 1;  
  10.       
  11.     private void dontStop(){  
  12.         while(true){  
  13.             try{Thread.sleep(1000);}catch(Exception err){}  
  14.         }  
  15.     }  
  16.       
  17.     public void stackLeakByThread(){  
  18.         while(true){  
  19.             Thread t = new Thread(new Runnable(){  
  20.   
  21.                 @Override  
  22.                 public void run() {  
  23.                     // TODO Auto-generated method stub  
  24.                     dontStop();  
  25.                 }  
  26.                   
  27.             });  
  28.             t.start();  
  29.             stackLength++;  
  30.         }  
  31.     }  
  32.       
  33.     public static void main(String[] args) throws Throwable{  
  34.         // TODO Auto-generated method stub  
  35.         StackOOM oom = new StackOOM();  
  36.         try{  
  37.             oom.stackLeakByThread();  
  38.         }catch(Throwable err){  
  39.             System.out.println("Stack length:" + oom.stackLength);  
  40.             throw err;  
  41.         }  
  42.           
  43.     }  
  44.   
  45. }  

报出异常:Exception in thread "main" java.lang.OutOfMemoryError:unable to create new native thread

不过在windows上运行这个例子要小心,会出现系统假死的情况,有可能需要重启机器才行。

以上几个例子虽然比较简单,但能很好帮助普通的程序员更加直观的了解Java堆方法区Java栈和本地方法栈

© 著作权归作者所有

思想永无止境
粉丝 4
博文 257
码字总数 292814
作品 0
昌平
程序员
私信 提问
JVM(二)Java虚拟机组成详解

导读:详细而深入的总结,是对知识“豁然开朗”之后的“刻骨铭心”,想忘记都难。 Java虚拟机(Java Virtual Machine)下文简称jvm,上一篇我们对jvm有了大体的认识,进入本文之后我们将具体...

王磊的博客
01/14
0
0
My java——JVM(内存域)三

续 My java——JVM(内存)二 写了一点JVM内存的一些操作的方法,和引出内存的分类。 是呀,java内存是我们在java编程中很少考虑到的,也没用真正的管理过。也许都知道JVM有自己的垃圾回收机...

tngou
2013/03/18
0
0
JVM虚拟机内存-学习笔记-超精简版-1

原文更详细:https://www.cnblogs.com/dingyingsi/p/3760447.html 程序计数器: 1、一块较小的内存空间,作用是当前线程所执行的字节码的行号指示器。(Java 虚拟机的多线程是通过线程轮流切...

Kidult
2018/08/07
0
0
JVM系列(二)—JVM内存结构

所有的Java开发人员可能会遇到这样的困惑?我该为堆内存设置多大空间呢?OutOfMemoryError的异常到底涉及到运行时数据的哪块区域?该怎么解决呢?其实如果你经常解决服务器性能问题,那么这些...

haoyuehong
2018/12/29
0
0
JVM 运行时数据区简介及堆与栈的区别

理解JVM运行时的数据区是Java编程中的进阶部分。我们在开发中都遇到过一个很头疼的问题就是OutOfMemoryError(内存溢出错误),但是如果我们了解JVM的内部实现和其运行时的数据区的工作机制,...

大数据之路
2015/08/02
0
1

没有更多内容

加载失败,请刷新页面

加载更多

Jenkins系列_插件安装及报错处理

进入Jenkins之后我们可以进行插件的安装,插件管理位于以下模块: 发现上面报了一堆错误,是因为插件的依赖没有安装好,那么这一节,就先把这些错误解决掉吧。解决完成后,也就基本会使用插件...

shzwork
今天
2
0
mysql mysql的所有查询语句和聚合函数(整理一下,忘记了可以随时看看)

查询所有字段 select * from 表名; 查询自定字段 select 字段名 from 表名; 查询指定数据 select * from 表名 where 条件; 带关键字IN的查询 select * from 表名 where 条件 [not] in(元素...

edison_kwok
昨天
9
0
多线程同时加载缓存实现

import com.google.common.cache.Cache;import com.google.common.cache.CacheBuilder;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorServi......

暗中观察
昨天
3
0
利用VisualVM 内存查看

准备工作,建几个测试类。等下就是要查看这几个类里面的属性 package visualvm;public class MultiObject { private String str; private int i; MultiObject(String str...

冷基
昨天
2
0
组装一台工作游戏两用机

一、配置清单如下: 分类 项目 价格(元) 主板 华硕(ASUS)TUF Z370-PLUS GAMING II 电竞特工 Z370二代 支持9代CPU 1049 CPU 英特尔(Intel) i7 8700K 酷睿六核 盒装CPU处理器 2640 风扇 九...

mbzhong
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部