目录

JVM内存区域概念

程序计数器(Program Counter Register)

Java虚拟机栈(Java Virtual Machine Stack)

本地方法栈(Native Method Stacks)

Java堆(Java Heap)

方法区(Method Area)

运行时常量池(Runtime Constant Pool)

直接内存(Direct Memory)


JVM内存区域概念


对于Java程序员来说,不用担负着每一对象从创建到销毁的维护任务,这个任务由Java虚拟机(JVM)的动态内存分配和垃圾收集技术来实现。

虽然JVM会自动对内存进行管理,但是一旦出现内存泄露和内存溢出的问题,如果不了解JVM是如何管理内存的,那排查错误、修正问题将会是一项困难的工作。
JVM在执行Java程序时,会把它所管理的内存划分为多个不同的数据区域,这些数据区域也称为运行时数据区域。
如图:

程序计数器(Program Counter Register)


程序计数器是一块较小的内存空间,可以看成是当前线程所执行的字节码的行号指示器。
在任何一个时刻,一个处理器只会执行一条线程中的指令,因此,为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,我们称这类内存区域为“线程私有”的内存。
如果线程正在执行的是一个Java方法,那计数器记录的是正在执行的字节码指令的地址;如果正在执行的本地(Native)方法,那么计数器的值为空(Undefined)。
该区域不会出现OutOfMemoryError异常。

Java虚拟机栈(Java Virtual Machine Stack)


Java虚拟机栈也是“线程私有”的,也就是每个线程都有一个独立的虚拟机栈内存,它的生命周期和线程相同。
线程执行一个方法的时候,JVM会在当前线程的虚拟机栈中同步创建一个栈帧(Stack Frame),用于存放局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
栈帧中的局部变量表,存放了编译期间可知的各种Java基本数据类型、对象引用和returnAddress类型。因此,当进入一个方法时,该方法在栈帧中需要分配多大的局部变量空间是完全确定的。
该区域会出现两种异常情况:
1)如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。
2)如果Java虚拟机栈可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。

本地方法栈(Native Method Stacks)


本地方法栈和虚拟机栈的作用很类似,区别的是,虚拟机栈执行的是Java方法服务,而本地方法栈是JVM使用到的本地(Native)方法服务。
本地方法栈也会在栈深度溢出或栈扩展失败时分别抛出StackOverflowError和OutOfMemoryError异常。

Java堆(Java Heap)


Java堆是JVM所管理的内存中最大的一块,而且它是被所有线程共享的一块内存区域。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
如果从分配内存的角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区(Thead Local Allocation Buffer,TLAB),以提升对象分配时的效率。
Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的。但对于大对象(如数组对象),多数虚拟机为了实现简单和存储高效,很可能会要求连续的内存空间。
Java堆的大小可以是固定的,也可以是可扩展的,当前主流的虚拟机都是按照可扩展来实现的,可以通过参数 -Xmx 和 -Xms 来设定。
如果Java堆中没有内存完成实例分配,并且堆也无法扩展时,JVM会抛出OutOfMemoryError异常。

方法区(Method Area)


方法区也是各个线程共享的内存区域,它用于存储被虚拟机加载的类型信息(Class对象)、常量、静态变量、即时编译器编译后的代码缓存等数据。方法区的另一个别名叫作“非堆”(Non-Heap)。
在JDK8之前,人们习惯把方法区叫作“永久代”(Permanent Generation),因为当时使用了永久代的方式实现了方法区。到了JDK8,完全废弃了永久代的概念,取代之的是“元空间”(Meta-space)和“字符串常量池”,把元空间移到了本地内存,把字符串产量池移到了Java堆中。
该区域的内存回收的目标主要是常量池的回收和对类型(Class对象)的卸载,一般来说这个区域的内存回收效率较低,尤其的类型的卸载,条件比较苛刻。
如果方法区无法满足新的内存分配时将抛出OutOfMemoryError异常。

运行时常量池(Runtime Constant Pool)


运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用,一般来说,JVM还会把符号引用翻译出来的直接引用也存储到运行时常量池中。
Java语言并不要求常量一定只有编译期才能产生,运行期间也可以将新的常量放入池中,如String类的intern()方法。
运行时常量池的内存受方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError 异常。

直接内存(Direct Memory)


直接内存并不是虚拟机运行时数据区的一部分。从JDK1.4开始,新加入了NIO类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据,如零拷贝技术。
直接内存受到本机直接内存的影响,从而导致动态扩展时出现 OutOfMemoryError 异常。

Java虚拟机(JVM)-1-内存区域相关推荐

  1. Java虚拟机JVM的内存管理

    Java虚拟机JVM的内存管理 关键词 一.JVM整体架构 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 名称 作用 特征 配置参数 异常 程序计数器 ...

  2. 一、JAVA虚拟机------JVM自动内存管理

    JVM自动内存管理 一.JAVA内存区与内存溢出 1.1 概述 1.2 运行时数据区 1.2.1 程序计数器 (Program Counter Register) 1.2.2 Java虚拟机栈(Jav ...

  3. java 启动内存参数_请问该如何设置Java虚拟机JVM启动内存参数?

    jps(JVM Process Status Tool):JVM机进程状况工具 用来查看基于HotSpot JVM里面所有进程的具体状态, 包括进程ID,进程启动的路径等等.与unix上的ps类似,用 ...

  4. Java虚拟机(JVM)的内存划分

  5. Java必突-JVM知识专题(一): Java代码是如何跑起来的+类加载到使用的过程+类从加载到使用核心阶段(类初始化)+类加载的层级结构+什么是JVM的内存区域划分?Java虚拟机栈、Java堆内存

    前言: 该章节知识点梳理:本文主要是入门和了解jvm,不做深入 1.Java代码是如何运行起来的? 2.类加载到使用的过程? 3.验证准备和初始化的过程? 4.类从加载到使用核心阶段:初始化.类加载器 ...

  6. 【深入Java虚拟机JVM 03】Java内存模型

    说明:文章所有内容均摘自<深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)> Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的"高墙",墙外面的 ...

  7. [转载] java虚拟机 jvm 出入java栈 栈空间内存分配

    参考链接: Java虚拟机(JVM)堆栈区域 java栈空间是一块线程私有的内存空间,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关.线程最基本的执行行为就是函数的调用.每次函数调 ...

  8. 深入理解Java虚拟机--JVM内存模型

    目录 一.运行时数据区域 1.程序计数器 2.Java 虚拟机栈 3.本地方法栈 4.Java 堆 5.方法区 6.运行时常量池 7.直接内存 二.OutOfMemoryError异常 1.Java堆 ...

  9. Java虚拟机(JVM)与Java内存模型(JMM)学习笔记

    Java虚拟机[JVM]与Java内存模型[JMM]学习笔记 Java虚拟机(JVM) 三种JVM JVM 位置 JVM的主要组成部分及其作用 类加载器 双亲委派机制 沙箱安全机制 Java本地接口( ...

  10. java heap 内存_深入理解jvm之内存区域与内存溢出

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器当前线程所执行的字节码的行号指示器 当前线程私有 不会出现OutOfMemoryError情况 java虚拟机栈线程私有,生命周期与线程相同 ...

最新文章

  1. 40 个 SpringBoot 常用注解
  2. Nginx调度器(反向代理),TCP/UDP调度器
  3. OpenCASCADE:建模算法之隐藏线去除
  4. oralce 11g data guard
  5. 商淘多b2b2c商城系统怎么在个人电脑上安装_企业怎么做好b2b2c商城网站建设?...
  6. Linux是命令行吗,你真的了解Linux命令吗?
  7. C语言文件拷贝-四种方式
  8. 23种设计模式(十一)对象性能之单件模式
  9. 360深度实践:Flink 与 Storm 协议级对比
  10. 高等数学下——平面与直线
  11. 如何进行自学软件测试?
  12. 多人联机游戏中联网模块(Socket)的设计和各种问题解决
  13. list列表 for循环
  14. 微信会不会封服务器ip,最新微信防封号设置技巧(新微信如何防止封号)
  15. Python基础笔记(二)整数缓存、字符串驻留机制、字符串格式化等
  16. 常见seo名词解释二(网站SEO常见术语说明)-从SEO到优化实战大师
  17. JAVA实现把PPT转PDF的方法
  18. AVEVA .Net 1.Introduction
  19. mysql144错误_MySQL 144错误
  20. k8s 动态NFS Subdir External Provisioner

热门文章

  1. Shell脚本常用判断
  2. 如何使用SQL删除某个字段重复的记录,保留其中一条
  3. Perl 标量的操作符
  4. 保存div与页面滚动条的位置
  5. python动态视频下载器
  6. 2008已经到来,我们怎能原地踏步!
  7. seleniuim面试题1
  8. 手机端页面要加...
  9. Python3 异常: name ‘basestring‘ is not defined
  10. Spring MVC BindingResult异常