JVM之Java内存结构

Java内存结构的几大部分如下图:

接下来,会对上面每部分区域的功能一一解释。

1、程序计数器:是线程私有区,是内存中一块较小的区域,是当前线程执行的字节码指令的行号指示器,如果线程执行的是Java方法,程序计数器记录的是正在执行的虚拟机字节码指令的地址,如果执行的是native方法,程序计数器存储的是undefined,此区域是内存中唯一一块没有规定任何OutOfMemoryError(内存溢出)情况的区域,为什么?因为我们不需要操作该区域,该区域是内部维护的。

2、虚拟机栈:是线程私有的,该区域所描述的是Java方法执行的动态内存模型,每个方法在执行的时候都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息,局部变量表存放的是编译期可知的基本数据类型,引用类型,returnAddress等,局部变量表的内存在编译期完成分配,进入方法后,这个方法需在帧中分配多少内存是固定的,在方法运行期间不会改变局部变量表的大小。如果说栈帧堆满了整个栈,会出现StackOverflowError(栈溢出)异常,栈也可以申请更大的内存,如果申请不到,会抛出OutOfMemoryError异常。

3、本地方法栈:是为本地的native方法服务的,其他的都和虚拟机栈一样。

4、堆:线程共享的一块区域,用来存放对象实例的(由于现在有了逃逸分析技术,也可以将对象分配在栈上),该区域是垃圾回收的主要区域,垃圾回收主要是分代回收,有年轻代和老年代,堆可以是物理上不连续的区域,只要逻辑上连续即可。在堆中分配内存的方法有碰撞指针(前提是区域绝对规整,注意多线程同步问题,可以采用CAS原理加失败重试实现或者本地线程分配缓冲)和空闲列表(不是规整的内存,就是有一个表记录空闲的内存,然后分配后,从该表中去除),堆空间不足时会出现OutOfMemoryError异常。

5、方法区:线程共享的区域,存储JVM加载的类信息(类的版本,字段,方法,接口),常量,静态变量以及即时编译后的代码等数据。方法区还有一块运行时常量池,class文件中的常量池在类加载后就被放入运行时常量池,运行时常量池相对于class文件的常量池具有动态性,可以在运行期间通过intern将常量放入运行时常量池中,方法区空间不足时会抛出OutOfMemoryError异常。

除了Java虚拟机规定的这几块区域以外呢,还存在一个堆外内存,即直接内存,直接内存能减少IO时的内存复制了,实现零拷贝,而且没有GC,减少了垃圾回收的工作,加快了复制的速度,该区域也难以控制,如果内存泄漏很难排查。

猜你喜欢

转载自www.cnblogs.com/javatalk/p/10146534.html