内存区域与内存溢出异常

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

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实战

扫描二维码关注公众号,回复: 4257142 查看本文章

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.

猜你喜欢

转载自www.cnblogs.com/c-lover/p/10025541.html