Java内存区域

Java内存区域学习

运行时数据区域

Java虚拟机在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域。根据《Java虚拟机规范》的规定,Java虚拟机所管理的内存包括如下图几个运行时数据区域。

java运行时数据区域图

(其中方法区和堆是所有线程共享的数据区。虚拟机栈、本地方法栈和程序计数器是线程隔离的数据区)

1.1 程序计数器(Program Counter Register)
  • 程序计数器是一块较小内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在Java虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖程序计数器拉完成。
  • Java虚拟机的多线程是通过线程轮流切换来分配处理器的执行时间的,因此当线程切换后要回到正确的执行位置,每个线程都需要一个线程私有的程序计数器来记录下一条需要执行的字节码指令,各个线程的计数器互不影响,独立存储。
1.2 Java虚拟机栈(Java Virtual Machine Stack)
  • Java虚拟机栈与程序计数器一样,也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的线程内存模型:每个方法被执行时,Java虚拟机都会同步创建一个栈帧用于存储局部变量表、操作数栈、动态连接和方法出口等信息。每一个方法从调用到执行完毕的过程中,都会对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
1.3 本地方法栈(Native Method Stack)
  • 本地方法栈与虚拟机栈所发挥的作用比较相似,其区别是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。
1.4 Java堆 (Java Heap)
  • 对于Java程序来说,Java堆是虚拟机所管理的内存中最大的一块空间,它是被所有线程共享内存的 一块内存区域,在虚拟机启动时创建。此内存区域是用来存放对象实例的,Java中几乎所有的对象实例都会在堆中分配内存。
  • Java堆是线程共享的,因此需要考虑线程安全问题
  • Java堆是垃圾收集器的内存区域,因此一些资料中它也被称作”GC堆“。从内存回收的角度看,由于现代垃圾收集器大部分基于分代收集理论设计,所以Java堆中经常会出现 “新生代”、“老年代”、“永久代”、“Eden空间(伊甸园)”、“From Survivor空间”、“To Survivor空间” 等名词。
  • 如果计算需要的堆多于自动存储管理系统所能提供的堆,Java 虚拟机将抛出一个 OutOfMemoryError.
1.5 方法区(Method Area)
  • 方法区和Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

  • 在方法区中,“永久代”这个概念在JDK1.8以前,很多人把方法区称呼为“永久代”(Permanent Generation),或将两者混为一谈。本质上两者并不等价,因为当时的HotSpot虚拟机设计团队选择把收集器的分代设计扩展到方法区,或者说是使用永久代来实现方法区,这样就使得HotSopt虚拟机的垃圾收集器可以像管理Java堆内存一样管理方法区内存,省去了专门为方法区编写内存管理代码的工作。但对于虚拟机来说,如IBM J9 、BEA Jrockit虚拟机来说是不存在永久代概念的。到了JDK1.8,完全废弃了永久代的概念,采用本地内存中实现的元空间(Meta-space)来代替。

    JDK6与JDK8内存结构如图
    jdk8与6

1.6 运行时常量池(Runtime Constant Pool)
  • 运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池,并把里面的符号地址变为真实地址。
  • 运行时常量池相较于Class文件常量池有一个重要的特征是具备动态性,Java语言并不要求常量一定只有在编译期间才能产生,在运行期间也可以将新的常量放入池中,这种特性使用得较多的是String类的intern()方法。
  • 在创建类或接口时,如果构建运行时常量池需要的内存多于 Java 虚拟机的方法区中可用的内存,则 Java 虚拟机将抛出一个OutOfMemoryError.
1.7直接内存(Direct Memory)
  • 直接内存不是虚拟机运行时数据区的一部分,但是这部分内存也被频繁的使用,而且也可能导致OutOfMemoryError异常出现。

  • 在JDK1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的IO方式,它可以使用Native函数直接分配堆外内存,然后通过一个存储在Java堆里的DirectByteBuffer对象作为这块内存的引用进行操作。这样在一些场景中能显著提高性能,常见于NIO操作,能使读写性能得到较大的提升,但分配内存和回收的成本也较高。而且不受JVM内存回收管理。

链接:JVM规范链接

相关书籍:深入理解Java虚拟机(周志明 著)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值