1.内存区域
Java虚拟机在执行Java程序的过程中会把管理的内存分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间。
1.1.程序计数器
当前线程执行字节码的行号指示器,通过改变计数器的值选取下一条执行的字节码指令,线程切换后恢复到正确的执行位置,跳转、循环等都依赖计算器来完成。每个线程都需要一个独立的程序计数器。唯一不会出现OOM的区域,为每个线程私有的。当执行的是Native方法时计数器的值为空。
1.2.Java虚拟机栈
Java虚拟机栈的生命周期与线程一样,每个方法被执行的时候会创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每个方法调用到执行完成的过程对应一个帧栈找虚拟机栈中入栈到入栈的过程。
局部变量表存放各种基本数据类型、对象引用,局部变量表所需的内存空间在编译器完成分配。
当所请求的栈的深度大于所允许的最大深度时会出现stackoverflow异常,当扩展无法申请足够的内存时,会抛出OOM。
1.3.本地方法栈
和虚拟机栈十分相似,只不过里面是以本地方法服务的。所以也会发生stackoverflow和OOM。
1.4.Java堆
一般来说Java堆是Java虚拟机管理的内存中最大的一块。Java堆是所有线程共享的内存区域,所有的对象实例已经数组都在堆上分配,但是随着JIT编译器的发展,并不是那么绝对了。
Java堆分为新生代和老年代,不同区域的垃圾回收处理不同。
1.5.方法区
方法区是线程共享的内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
1.6. 运行常量池
是方法区的一部分。Class文件中一项信息是常量池,用于存放编译期间生成的各种字面量和符号引用。这部分内容在类加载后进入方法区的运行时常量池中存放。
1.7. 直接内存
并不是虚拟机运行时数据区的一部分,也不是JAVA虚拟机规范中定义的内存区域,但是这部分区域被频繁使用,同时也会出现OOM。
NIO中,引入了一种基于通道和缓冲区的IO方式,使用Native库直接分配堆外内存,然后通过一个存储在JAVA堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样能用显著提升性能,避免了在Java堆和Native堆中来回复制数据。
直接内存不会受到JAVA堆大小的限制,会受到本机中内存的限制。
2. 对象访问
存在两种方式:
(1).通过句柄的方式,会在堆中单独划出一块内存当做句柄池。
(2).reference直接存储对象地址。