深入理解Java虚拟机读书笔记(一)

一、JDK与JRE

JDK:通常把Java程序设计语言、Java虚拟机、Java API类库这三部分统称为JDK(Java Development Kit),它是支持Java开发的最小环境。
JRE:通常把Java API类库中的Java SE API子集和Java虚拟机这两部分统称为JRE(Java Runtime Environment),它是支持Java程序运行的标准环境。

二、运行时数据区域

  1. Java虚拟机在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域。


    Java虚拟机运行时数据区.png
  2. 程序计数器:一块较小的内存空间,可以通过改变这个计数器的值来选取下一条需要执行的字节码指令。它是唯一一块在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。如果线程执行的是一个Java方法,则这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器的值为空。
  3. Java虚拟机栈:
    虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的时候都会创建一个栈帧用于存放局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用到完成,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
    局部变量表存放了各种编译期可知的基本数据类型(boolean,byte,char,short,int,float,double,long)、对象引用(引用类型,它不同于对象本身,可能是指向对象初始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象有关的位置)、returnAddress类型(指向一条字节码指令的地址)。它所需的内存空间在编译时完成分配。
    这个区域有两种异常情况:当线程请求的栈深度大于虚拟机允许的栈深度时,会抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,当扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
  4. 本地方法栈:与Java虚拟机栈类似,它是为Native方法服务的,并且对方法的实现语言没有限制。
  5. Java堆:Java虚拟机管理内存中最大的一块,在虚拟机启动时创建,为线程共享。存放对象实例,几乎所有对象实例都在这里分配内存。它是垃圾收集器管理的主要区域。
  6. 方法区:存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
  7. 运行时常量池:方法区的一部分,存放类加载后进入方法区运行时常量池的编译期生成的各种字面量和符号引用。它具有动态性,在运行时也可在池中放入新的常量。常用的有String的intern()方法。
  8. 直接内存:不属于Java虚拟机运行时数据区的一部分,但被频繁使用。如NIO类引入的一种基于通道(Channel)和缓冲区的I/O方式。它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。

三、对象的访问定位

  1. 通过句柄访问对象:java堆中分出一块内存作为句柄池,reference中存储的是对象的句柄地址,句柄中包含了对象实例数据和类型数据各自的具体地址信息。
    使用句柄的最大好处是reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是很普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改。


    通过句柄访问对象.png
  2. 使用直接指针访问:需考虑如何放置访问类型数据的相关信息,reference中存储的直接就是对象地址。
    直接指针访问的最大好处是访问速度快,节省了一次指针定位的时间开销。


    通过直接指针访问对象.png

四、java内存溢出异常

  1. java堆溢出(java.lang.OutOfMemoryError: Java heap space)
package cn.wxz1997.concurrency.jvm;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description: VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 * 参数依次为堆最小值,最大值,最后一个参数可以使虚拟机在内存溢出时Dump出当前的内存堆转储快照以便分析
 * @Author: wxz1997
 * @Date 18-7-11下午4:14
 */
public class HeapOOM {

    static class OOMObject{

    }

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

  1. 虚拟机栈和本地方法栈溢出
package cn.wxz1997.concurrency.jvm;

/**
 * @Description: VM Args:-Xss228k 该参数Xss设定每个线程的堆栈大小
 * @Author: wxz1997
 * @Date 18-7-11下午4:45
 */
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;
        }


    }
}

  1. 方法区和运行时常量池溢出
  2. 本机直接内存溢出

你可能感兴趣的:(深入理解Java虚拟机读书笔记(一))