初学Java虚拟机(二):Java内存区域

学习了初学Java虚拟机(一):Java技术体系后,继续学习,本文主要记录Java内存区域相关知识

Part II: 自动内存管理机制

第2章 Java内存区域与内存溢出异常

概述

Java程序中,虚拟机有自动内存管理机制,不再需要为每个new操作去写配对的delete/free代码,不容易出现内存泄漏和内存溢出问题。但是一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会成为一次异常艰难的工作。

运行时数据区域

JVM运行时数据区
上图:JVM运行时数据区,引自《深入理解Java虚拟机》读书笔记–vernlium

程序计数器(Program Counter Register)
  • 程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器;
  • 每条线程都有一个独立的程序计数器,各条线程之间计数器互不影响,称之为“线程私有”的内存;
  • 如果线程执行的是Java方法,该计数器记录的是正在执行的虚拟机字节码指令的地址;如果是Native方法则为空;
  • 此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域;
Java虚拟机栈(Java Virtual Machine Stack)

虚拟机栈)
上图引用自:《Java虚拟机原理图解》3、JVM运行时数据区

  • Java虚拟机栈是线程私有,它的生命周期与线程相同;
  • Java虚拟机栈描述的是Java方法执行的内存模型:每个方法在在执行的同时都会创建一个栈帧(Stack Frame)用于存储 局部变量表操作数栈动态链接方法接口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈出栈的过程;
  • 局部变量表存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和returnAddress类型;其所需的内存空间在编辑期完成分配,不会在运行期改变;
  • 可能存在两种异常:StackOverflowError和OutOfMemoryError;
本地方法栈(Native Method Stack)
  • 与虚拟机栈所发挥的作用非常相似,区别是虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则为虚拟机使用到的Native方法服务;
  • 可能存在两种异常:StackOverflowError和OutOfMemoryError;
Java堆(Java Heap)
  • Java堆是被所有线程共享的,在虚拟机启动时创建;
  • 此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这分配;
  • 是垃圾收集器管理的主要区域,可以分为新生代和老年代;
  • 可以物理不连续,只要逻辑上是连续的即可;
  • 如果堆中没有内存完成实例分配也无法再扩展时,会抛出OutOfMemoryError异常;
方法区(Method Area)

方法区
上图引用自:《Java虚拟机原理图解》3、JVM运行时数据区

  • 是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;
  • 永久代:JavaGC的分代收集机制分为3个代:年青代,老年代,永久代,将方法区定义为“永久代”,这是因为,对于之前的HotSpot Java虚拟机的实现方式中,将分代收集的思想扩展到了方法区,并将方法区设计成了永久代。不过,除HotSpot之外的多数虚拟机,并不将方法区当做永久代,随着Java8的到来,已放弃永久代改为采用Native Memory来实现方法区的规划。
  • 当无法满足内存分配需求时,将抛出OutOfMemoryError异常;
运行时常量池(Runtime Constant Pool)
  • 是方法区的一部分;
  • Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,在部分内容将在类加载后进入方法区的运行时常量池中存放;
  • 运行时常量池相对于Class文件常量池,具有动态性,运行期间也可以将新的常量放入常量池,比如String类的intern()方法;
  • 当运行时常量池无法申请到更多的内存时,将会抛出OutOfMemoryError异常;
直接内存(Direct Memory)
  • 并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域;
  • JDK 1.4的NIO引入了基于通道(Channel)和缓冲区(Buffer)的IO方法,可以使用Native函数库直接分配对外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作以提升性能;
  • 设置Xmx等参数信息时注意不能忽略直接内存,不然会引起OutOfMemoryError异常;

猜你喜欢

转载自blog.csdn.net/tian330726/article/details/81558703
今日推荐