内存区域与内存溢出异常

第二章 内存区域与内存溢出异常

2.2 运行时数据区域

2.2.1 程序计数器

    程序计数器是当前程序执行的字节码的行号指示器,通过改变程序计数器的值可以实现	              分支,跳转,循环,异常,线程回复等功能

   ### 2.2.2 Java虚拟机栈和本地方法栈

      线程私有,与线程的生命周期相同。方法执行时在此处创建栈帧用于储存局部变量表,操作数栈,动态链接,方法出口的那个信息。

2.2.3本地方法栈

	也是线程私有,与线程生命周期相同。它为执行本地方法提供服务

2.2.4 java堆

	被所有线程共有,可以分为Eden ,From Survivor ,To Survivor .创建对象时在堆上分配内存,也是垃圾收集器管理的主要区域。

2.2.5方法区

	所有线程共享,用于储存虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。在HotSpot中也被称为永久代

2.2.6运行时常量池

	它是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。运行期可以使用String.intern()方法使字符进入常量池

2.2.7直接内存

	我觉得就是本机内存,没有什么特别的。

2.3对象

2.3.1对象的创建

	先检查这个指令的参数是否能在常量池中定位到类的符号引用,并且检查符号引用的类是否被加载,解析,初始化,如果没有就去加载。然后分配内存,初始化为0值,设置元数据信息,对象的hash码,GC分代年龄,。

2.4实战

2.4.1 java 堆溢出

package memoryTest;


/**
 * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 * @author 洪buff
 */
import java.util.ArrayList;
import java.util.List;

public class HeapMain {
	static class OOMObject{
		
	}
	
	public static void main(String[] args){
		List<OOMObject> list=new ArrayList<OOMObject>();
		while(true){
			list.add(new OOMObject());
		}
	}

}

2.4.2本地方法栈和虚拟机栈溢出

package memoryTest;

/**
 * VM Args: -Xss128K
 * @author 洪buff
 *
 */
public class JavaVMStackSOF {
	private int stackLength=1;
	public void stackLeak(){
		stackLength++;
		stackLeak();
	}
	
	public static void main(String[] args)throws Throwable{
		JavaVMStackSOF oom=new JavaVMStackSOF();
		try{
			oom.stackLeak();;
			
		}catch (Throwable e) {
			System.out.println("stack length:"+oom.stackLength);
			throw e;
		}
	}

}




### 2.4.3本地方法栈溢出

package memoryTest;

/**
 * VM Args:-Xss2M(或者更大)
 * @author 洪buff
 *
 */
public class JavaVMStackOOM {
	private void dontStop(){
		while(true){
			
		}
	}
	
	public void stackLeakByThread() {
		while (true){
			Thread thread =new Thread(new Runnable(){

				@Override
				public void run() {
					dontStop();
					
				}
				
			});
			thread.start();
		}
		
	}
	
	public static void  main(String[] args) {
		JavaVMStackOOM oom=new JavaVMStackOOM();
		oom.stackLeakByThread();
		
	}
	

}

很危险,我不做演示

2.4.3方法区和运行时常量中intern

package memoryTest;

public class RuntimeConstanPoolOOM {
	
	public static void main(String[] args) {
		String str1=new StringBuilder("计算机").append("软件").toString();
		System.out.println(str1.intern()==str1);
		
		String str2=new StringBuilder("ja").append("va").toString();
		System.out.println(str2.intern()==str2);
	}

}

分析:StringBuilder在堆中创建字符串对象“计算机软件",intern()方法将它的引用复制到了字符串常量池,所以答案是true.

    "java"第一次被创建是在类加载时,在常量池中加载,而str2则是指向堆中的”java"对象,intern()方法返回的时常量池中的“java"所以答案是false.
posted @ 2018-11-27 11:51  李成洪  阅读(121)  评论(0编辑  收藏  举报