前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java虚拟机内存管理(一)—内存划分

Java虚拟机内存管理(一)—内存划分

作者头像
Wizey
发布2018-09-29 09:46:11
8640
发布2018-09-29 09:46:11
举报
文章被收录于专栏:编程心路

Java 与 C++ 之间有一堵由内存动态分配和垃圾收集技术所围成的 “高墙”,墙外面的人想进去,墙里面的人却想出来。——《深入理解Java虚拟机:JVM高级特性与最佳时实践(第二版)》周志明

Java 虚拟机作为运行 Java 程序抽象出来的计算机,具有内存管理的能力,像内存分配、垃圾回收等这些相关的内存管理问题,Java 虚拟机都会帮我们解决,所以作为一个 Java 程序员要比 C++ 程序员幸福,但是内存方面一旦出现问题,如果对虚拟机怎样使用内存不了解,就很难排查错误。

这段时间看周志明先生的《深入理解Java虚拟机:JVM高级特性与最佳时实践(第二版)》,下面就对 Java 虚拟机对内存的管理做一个系统的整理,本篇文章是该专题的第一篇。

1、内存划分

内存是计算机中运行系统和软件的场所,而内存划分是 Java 虚拟机管理内存中人为添加的概念,是为了更好的描述 Java 虚拟机对内存的管理。下图中的的运行时数据区域即是 Java 虚拟机所管理的内存区域。

内存划分.png

1.1 程序计数器

在 CPU 的寄存器中有指令计数器,而在 Java 虚拟机内存管理中也有类似的程序计数器。程序计数器占用一块很小的内存空间,并且每条线程中都有独立的程序计数器。指令计数器记录的是 CPU 将要执行的下一条指令的地址,而程序计数器略有不同。在线程执行的 Java 方法时,程序计数器记录的是正在执行的虚拟机字节码指令的地址,而在线程执行 Native 方法时,程序计数器为空,因为此时 Java 虚拟机调用是和操作系统相关的接口,与 Java 语言无关。

此区域是唯一一个在 Java 虚拟机规范中没有规定会出现 OutOfMemoryError 情况的区域,对 OutOutOfMemoryError 的讲解会在后面说到。

1.2 Java 虚拟机栈

我们常在程序运行的内存划分为堆区和栈区,但是在 Java 中,这样的划分是很粗糙的,Java 虚拟机中栈有 Hava虚拟机栈和本地方法栈。同程序计数器一样,Java 虚拟机栈也是每条线程私有的。虚拟机栈描述的是 Java 方法执行时的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。栈这种数据结构,就不多说了,特点是先进先出(FIFO),而栈帧就是栈中的数据元素,下图中是栈帧的这种数据在 Java 栈中的结构图。

栈帧数据结构.png

局部变量表中存放的是编译期可知的各种基本数据类型,包括 Java 的八大基本数据类型和对象引用(reference)类型(这种类型不在这里详细说了)。一个方法需要在帧中分配多大的局部变量空间是完全确定的,并且在其方法运行期间不会改变局部变量表的大小,进而可以知道局部变量表所需的内存空间在编译期就确定下来了。

在 Java 虚拟机规范中,对这个区域规定了两种异常出现的情况:

  • 如果线程请求的栈深度大于虚拟机所允许的深度,抛出 StackOverflowError 异常。
  • 如果虚拟机栈在动态扩展时无法申请到足够的内存,抛出 OutOfMemoryError 异常。

1.3 本地方法栈

本地方法栈和虚拟机栈作用是相似的,他们之间的区别无非是虚拟机栈为虚拟机执行的是 Java 方法,本地方法栈为虚拟机使用的是 Native 方法。其实,不同的 Java 虚拟机,对栈区域的实现是不同的,比如主流的 HotSpot 虚拟机就把虚拟机栈和本地放栈合二为一了。

与虚拟机栈一样,本地方法栈也会抛出 StackOverflowError 和 OutOfMemoryError 异常。

1.4 Java 堆

Java 堆是 Java 虚拟机内存所管理的内存最大的一块,所有的线程都共享此区域,此区域可以说是 Java 对象的出生地,此区域的唯一目睹就是存放 Java 实例,几乎所有的对象实例都在这里分配内存(不同的编译器有所不同)。Java 堆也是垃圾收集器管理的主要区域,也被称为是 “GC堆”。Java 堆在物理上可以处于不连续的内存空间,只要在逻辑上是连续的就可以了,就像磁盘空间存放文件一样。Java 堆既可以是固定大小的,也可以是可扩展的,在主流的 java 虚拟机中是按照可扩展来实现的。关于 Java 堆的详细介绍将在后面说明。

如果在 Java 堆中没有足够的内存空间完成对象实例的分配,并且堆也无法再扩展,将会抛出 OutOfMemoryError 异常。

1.5 方法区

同 Java 堆一样,方法区也是各个线程共享的区域,它用于存储已经被虚拟机加载过的类信息、常量、静态变量、即时编译器编译后的代码等数据。Java 虚拟机规范中把方法区描述为堆的一个逻辑部分,也叫做 “非堆”,也是为了和 Java 堆区分开来。方法区和 Java 堆一样,也不需要连续的内存空间,在 Java 虚拟机的实现中,也是可以选择固定大小或者可扩展,并且还可以选择不实现垃圾回收,因为这个区域需要用到回收的地方很少,但是实际开发种的教训告诉我们,对方法区进行垃圾回收也是很有必要的,这个区域同样会出现内存泄漏的问题。

在方法区中,有一部分被称为是运行时常量池。常量池除了用于存放在编译期生成的各种字面量和符号引用,此外还有直接引用也被存储在运行时常量池中。运行时常量池具有动态性,常量并不一定实在编译期才被放入该常量池,在运行期间也可以有新的常量放入池中,如我们在开发中使用 String 类的 intern() 方法时。

对字面量和符号引用不清楚的小伙伴可以看下面两篇扩展阅读。

字面量,常量和变量之间的区别?

个人理解 java虚拟机中的符号引用和直接引用

方法区中并不是像字面意思那样存放方法的,它很像一个Java世界的身份信息中心,类,常量、变量的信息都有。——个人理解

当方法区无法满足内存分配时,抛出 OutOfMemoryError 异常。

1.6 直接内存

直接内存并不在 Java 虚拟机管理的内存区域内,也不是 Java 虚拟机规范中定义的内存区域。直接内存是 Java 程序不经过 Java 虚拟机分配,直接使用主机的物理内存,在一些场景(如文件赋值)中可以提高性能,但是直接在使用直接内存中也要注意主机内存大小的限制(包括物理和系统级的限制),否则也会抛出 OutOfMemoryError 异常。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.08.30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、内存划分
    • 1.1 程序计数器
      • 1.2 Java 虚拟机栈
        • 1.3 本地方法栈
          • 1.4 Java 堆
            • 1.5 方法区
              • 1.6 直接内存
              相关产品与服务
              对象存储
              对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档