从几个sample来学习Java堆,方法区,Java栈和本地方法栈

本文通过具体示例介绍了Java运行时数据区域的结构,包括Java堆、方法区、Java栈和本地方法栈。每个部分都提供了代码示例和JVM参数配置,展示了不同条件下出现OutOfMemoryError的具体场景。

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

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

1)Java堆

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

[java] view plain copy
  1. publicclassHeapOOM{
  2. staticclassOOMObject{}
  3. /**
  4. *@paramargs
  5. */
  6. publicstaticvoidmain(String[]args){
  7. List<OOMObject>list=newArrayList<OOMObject>();
  8. while(true){
  9. list.add(newOOMObject());
  10. }
  11. }
  12. }

加上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. publicclassMethodAreaOOM{
  2. staticclassOOMOjbect{}
  3. /**
  4. *@paramargs
  5. */
  6. publicstaticvoidmain(String[]args){
  7. //TODOAuto-generatedmethodstub
  8. while(true){
  9. Enhancereh=newEnhancer();
  10. eh.setSuperclass(OOMOjbect.class);
  11. eh.setUseCache(false);
  12. eh.setCallback(newMethodInterceptor(){
  13. @Override
  14. publicObjectintercept(Objectarg0,Methodarg1,
  15. Object[]arg2,MethodProxyarg3)throwsThrowable{
  16. //TODOAuto-generatedmethodstub
  17. returnarg3.invokeSuper(arg0,arg2);
  18. }
  19. });
  20. eh.create();
  21. }
  22. }
  23. }

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

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

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

[java] view plain copy
  1. publicclassConstantOOM{
  2. /**
  3. *@paramargs
  4. */
  5. publicstaticvoidmain(String[]args){
  6. //TODOAuto-generatedmethodstub
  7. List<String>list=newArrayList<String>();
  8. inti=0;
  9. while(true){
  10. list.add(String.valueOf(i++).intern());
  11. }
  12. }
  13. }

同样加上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. packagecom.cutesource;
  2. publicclassStackOOM{
  3. /**
  4. *@paramargs
  5. */
  6. privateintstackLength=1;
  7. publicvoidstackLeak(){
  8. stackLength++;
  9. stackLeak();
  10. }
  11. publicstaticvoidmain(String[]args)throwsThrowable{
  12. //TODOAuto-generatedmethodstub
  13. StackOOMoom=newStackOOM();
  14. try{
  15. oom.stackLeak();
  16. }catch(Throwableerr){
  17. System.out.println("Stacklength:"+oom.stackLength);
  18. throwerr;
  19. }
  20. }
  21. }

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

Exception in thread "main" java.lang.StackOverflowError

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

[java] view plain copy
  1. packagecom.cutesource;
  2. publicclassStackOOM{
  3. /**
  4. *@paramargs
  5. */
  6. privateintstackLength=1;
  7. privatevoiddontStop(){
  8. while(true){
  9. try{Thread.sleep(1000);}catch(Exceptionerr){}
  10. }
  11. }
  12. publicvoidstackLeakByThread(){
  13. while(true){
  14. Threadt=newThread(newRunnable(){
  15. @Override
  16. publicvoidrun(){
  17. //TODOAuto-generatedmethodstub
  18. dontStop();
  19. }
  20. });
  21. t.start();
  22. stackLength++;
  23. }
  24. }
  25. publicstaticvoidmain(String[]args)throwsThrowable{
  26. //TODOAuto-generatedmethodstub
  27. StackOOMoom=newStackOOM();
  28. try{
  29. oom.stackLeakByThread();
  30. }catch(Throwableerr){
  31. System.out.println("Stacklength:"+oom.stackLength);
  32. throwerr;
  33. }
  34. }
  35. }

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值