Java面试——JVM(2)

1、程序计数器(线程私有)

  • 线程执行字节码的行号指示器(注意是字节码,本地方法计数器为空的)

2、Java虚拟机栈(线程私有):

  • 描述的是Java方法执行的内存模型
  • 每一个方法对应一个栈帧
  • 栈帧包含:局部变量表、操作数栈、动态链接、方法出口
  • 局部变量表slot会复用,导致一些对象不能被及时的回收,所以建议对象不用之后要赋值为空;
  • 局部变量表在编译器就已经完成分配
  • 方法的返回地址即方法出口有二:正常完成方法(如有返回值则是return的地方)方法异常时异常块(如果没有finally的情况下)
public void clear() {      //   此处若有参数,参数也属于局部变量表

    Node[] tab;                // tab 是 对象引用

    modCount++;            // ++ 是在操作数栈中    modCount属于类实例的属性值,在堆中

    if ((tab= table) != null && size> 0) {

        size= 0;

        for (int i= 0; i< tab.length; ++i)

            tab[i] = null;

    }

    // 这里是方法出口

}

本地方法栈(线程私有)

  • 抛异常如Java虚拟机栈,不过是服务于本地方法的

Java堆(线程共享)

  • 几乎所有的实例都在这里分配内存(因为JIT和逃逸技术发展导致了不是绝对的所有)

方法区(线程共享)

  • 存储 已被虚拟机加载的类信息(即每个类的class类)、常量、静态变量、即时编译后的代码(第一次编译后的代码)

运行时常量池(属于方法区的一部分)

  • 存放编译期的字面量和符号引用

    字面量:String str=”abc” 中的”abc” int i = 1;中的 1

    符号引用:就是类引用(类的全路径)

  • String类中intern()方法就是运行期间将新的常量放入池中,class文件的动态性及并不是只有在编译期产生常量

直接内存

  • NIO中使用native方法直接分配堆外内存
  • 使用Java堆中的DirectByteBuffer对象作为这块引用进行操作

OOM

  • 可以出现OOM的一般场景
    • 创建对象超出了最大堆
    • 创建了太多的线程
      • 如果想创建很多线程又不能OOM,就需要减小最大堆和减少栈容量
    • 虚拟机进行扩展栈失败时
    • 框架中可能出现字节码技术导致方法区溢出
    • 在如Netty等使用NIO的通信框架中可能导致直接内存溢出

猜你喜欢

转载自blog.csdn.net/AJ1101/article/details/81671815