zoukankan      html  css  js  c++  java
  • 笔记:深入理解JVM 第2章 Java内存区域与内存溢出

    1、JVM 运行时数据区

    所有线程共享的数据区:方法区(持久代)、堆区

    线程隔离的数据区:程序计数器、Java虚拟机栈区


    堆区构成:新生代 ( 由Eden, From Survivor, To Survivor 构成)、老生代

    运行时常量池:方法区一部分,用于存放编译期生成的各种字面量和符号引用

    直接内存:不是JVM 运行时数据区的一部分,不受Java堆大小限制,但是受物理内存限制,也会抛出 OutOfMemoryError。Java NIO 中的DirectByteBuffer 使用了直接内存。


    2、OutOfMemoryError 案例


    (1)、堆溢出

    在对象数量达到最大堆容量限制后,发生堆内存溢出异常 OutOfMemoryError: Java heap space 。

    JVM配置:

    -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

    代码:

    public static void main(String[] args) {
    		 List<Object>  list = new LinkedList<Object>();
    		 for(int i=0;i<Long.MAX_VALUE;i++)
    		 {
    			 list.add(new XX());			 
    		 }
    	}


    输出:

    java.lang.OutOfMemoryError: GC overhead limit exceeded
    Dumping heap to java_pid4192.hprof ...
    Heap dump file created [37582435 bytes in 0.265 secs]
    Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
    	at java.util.LinkedList.linkLast(Unknown Source)
    	at java.util.LinkedList.add(Unknown Source)
    	at chapter2.HeapOver.main(HeapOver.java:14)


    使用Eclipse Memory Analyzer 分析生成的Dump文件:java_pid4192.hprof

    快照



    (2).栈溢出

    线程的请求栈深度大于虚拟机所允许最大深度,将抛出StackOverflowError

    如果虚拟机在扩展栈时候无法申请得到足够的内存空间,将抛出OutOfMemoryError


    JVM配置:

    -Xss128k


    单线程代码: 

    public class StackOverExam1 {
    
    	public int stackLength = 1;
    
    	public void methed1() {
    		System.out.println("Stack Length:" + stackLength++);
    		if(stackLength < Long.MAX_VALUE) 
                    {  
                        methed1();  
                    }
    	}
    
    	public static void main(String[] args) {
    		StackOverExam1 exam = new StackOverExam1();
    		exam.methed1();
    	}
    
    }


    抛出异常:

    Stack Length:987
    Stack Length:988
    Exception in thread "main" java.lang.StackOverflowError
    	at java.nio.Buffer.<init>(Unknown Source)
    	at java.nio.CharBuffer.<init>(Unknown Source)
    	at java.nio.HeapCharBuffer.<init>(Unknown Source)
    	at java.nio.CharBuffer.wrap(Unknown Source)
    	at sun.nio.cs.StreamEncoder.implWrite(Unknown Source)
    	at sun.nio.cs.StreamEncoder.write(Unknown Source)

    在单线程下,无论是栈帧太大还是虚拟机容量太小,当内存无法分配时候,虚拟机抛出的都是StackOverflowError。

    多线程情况下,-Xss设置得越大,即为每个线程栈分配内存越大,越容易抛出 OutOfMemoryError: unable to create new native thread


    多线程时候JVM配置:
    -Xss2m

    多线程代码:
    public static void main(String[] args) {
    		 
    		for(long i=0;i<Long.MAX_VALUE;i++)
    		{
    			System.out.println("Thread Num:"+ (++i));
    			new Thread(new Runnable()
    			{
    
    				@Override
    				public void run() {
    					while(true)
    					{
    						
    					}					
    				}
    				
    			}).start();
    		}
    	}


    抛出异常:

    ava.lang.OutOfMemoryError: unable to create new native thread


    (3). 对象常量池和方法区溢出

    抛出 OutOfMemory: PermGen space


    常量池溢出例子:

    String.intern() 是一个Native方法,其作用是:若字符串常量池包含此String对象,则返回该对象;否则将其加入到常量池中,再返回。 

    JVM配置:

    -XX:PermSize=10m -XX:MaxPermSize=10m

    代码:

    public class RuntimeConstPoolOver {
     
    	public static void main(String[] args) {
    		List<String> list = new LinkedList<String>();
    		for (int i = 0; i < Long.MAX_VALUE; i++) {
    			//System.out.println(i);
    			list.add(String.valueOf(i).intern());
    		}
    	}
    
    }


    JDK1.6 输出: 

     java.lang.OutOfMemoryError: PermGen space

    JDK 1.7 不会有错误

    方法区溢出例子:

    Spring、Hibernate 等框架会使用CGLib技术,将动态生成的Class载入方法区,当方法区太小时,引发 

     java.lang.OutOfMemoryError: PermGen space

      

    (4).直接内存溢出

    DirectMemory 容量可通过 -XX: MaxDirectMemorySize 制定,若无制定则与JVM堆的最大值(-Xmx) 一样。

    判断是否由DirectMemory的溢出条件:

    a. Heap Dump 文件不会看到明显异常,文件很小

    b. 程序中直接或间接使用了NIO


    例子JVM配置:

    -Xmx20M -XX:MaxDirectMemorySize=20M


    代码:

    import java.lang.reflect.Field;
    import sun.misc.Unsafe;
    
    public class DirectMemoryOver {
    
    	public static void main(String[] args) throws IllegalArgumentException,
    			IllegalAccessException {
    
    		long _100M = 100 * 1024 * 1024;
    		Field f = Unsafe.class.getDeclaredFields()[0];
    		f.setAccessible(true);
    		Unsafe unsafe = (Unsafe) f.get(null);
    		for (int i = 0; i < Long.MAX_VALUE; i++) {
                System.out.println(i);
    			unsafe.allocateMemory(_100M);
    		}
    	}
    
    }
    


    输出:

    126
    Exception in thread "main" java.lang.OutOfMemoryError
    	at sun.misc.Unsafe.allocateMemory(Native Method)
    	at chapter2.DirectMemoryOver.main(DirectMemoryOver.java:17)










    	
  • 相关阅读:
    浏览器 显示一个对话框,对话框中包含一条文字信息,用来提示用户输入文字。window.prompt()
    JS字符串转换为JSON对象的四种方法
    js中 json对象与json字符串相互转换的几种方式 $.parseJSON(jsonStr)json字符串转换为json对象
    C#变量命名规则(命名规范)
    C#中AppDomain.CurrentDomain.BaseDirectory(获取程序的基目录)及各种路径获取方法
    C# 的 Path.GetFileName、Path.GetExtension、Path.GetDirectoryName千一网络 http://www.itpow.com/
    js计算两个时间相差天数,获取时间的毫秒数之差
    C#将DataTable转化为List<T>
    https://www.cnblogs.com/sizhizhiyue/p/4820973.html asp.net后台导出excel的方法一:使用response导出excel
    .NET调用AS/400上的程序(.NET CALL AS/400 PGM)
  • 原文地址:https://www.cnblogs.com/leeeee/p/7276311.html
Copyright © 2011-2022 走看看