深入理解Java虚拟机-内存管理-数据区划分

1、概述

相较于C和C++来说,Java开发人员不需要主动管理内存,在虚拟机管理机制的帮助下,不容易出现内存溢问题,由虚拟机管理的内存运行稳定。但是一旦出现问题,如果不了解虚拟机怎样使用内存,那么查错将异常艰难。

2、运行时数据区

Java虚拟机把它所管理的内存划分为若干区域,每个区域有个字用途以及创建销毁的时间

 

2.1 程序计数器

程序计数器是一块较小的内存空间,可看作当前线程正在执行的字节码的行号指示器,为线程私有,即每个线程都有自己的计数器

如果当前线程正在执行的是

  • Java方法计数器记录的就是当前线程正在执行的字节码指令的地址 

  • 本地native方法那么程序计数器值为undefined

2.2 虚拟机栈(JVM Stack)

生命周期与线程相同,线程私有,描述的是Java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧存储局部变量表(存放方法参数和局部变量)、操作数栈、动态链接,方法出口等信息,每一个方法从调用直至执行完成的过程,就对应一个栈帧在虚拟机中的入栈出栈过程

在此区域规定了两种异常,分别为:

  • StackOverflowError :线程请求栈深度大于虚拟机所允许的深度
  • OutOfMemoryError:虚拟机栈拓展时无法申请到足够的内存

 

2.3 本地方法栈(Native Method Stack)

与虚拟机栈发挥的作用相似,区别为虚拟机栈执行的为java方法,本地方法栈执行的是native方法,本地方法栈也会抛出StackOverflowError 错误

2.4 堆(Java Heap)

 是Java虚拟机锁敷哪里的内存中最大的一块。是被所有线程锁共享的一块内存区域,在虚拟机启动时创建用于存放对象实例,线程共享

Java堆是垃圾收集器管理的主要区域,也被称为GC堆,从内存回收角度看,堆还可细分为新生代和老年代,再细致新生代还有Eden空间、From Survivor空间,To Survivor空间;从内存分配角度看,线程共享的堆可能划分出多个线程私有的分配缓冲区。

堆的内存空间既可以固定大小,也可运行时动态地调整,通过如下参数设定初始值和最大值,比如

-Xms256M -Xmx1024M

当线程请求分配内存,但堆已满,且内存已满无法再扩展时,就抛出OutOfMemoryError

2.5 方法区

Java虚拟机规范中定义方法区是堆的一个逻辑部分,又名Non-Heap(非堆),目的是与Java堆区分,线程共享

方法区中存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

HotSpot把GC分代拓展至方法区,省去专门为方法区编写内存管理代码的工作。

2.6 运行时常量池

是方法区的一部分,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放,也可抛出OutOfMemoryError异常

2.7 直接内存

不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。JDK1.4后加入NIO(new Input/Output)类,引入一种基于通道于缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,可以在部分场景中显著提高性能,因为避免了在堆和Native堆中来回复制数据

 

 参考《深入理解Java虚拟机》---周志明

posted @ 2019-08-25 11:00  一个疯子丶  阅读(142)  评论(0)    收藏  举报