java内存机制详解

上传人:ji****en 文档编号:107704873 上传时间:2019-10-20 格式:PDF 页数:35 大小:829.51KB
返回 下载 相关 举报
java内存机制详解_第1页
第1页 / 共35页
java内存机制详解_第2页
第2页 / 共35页
java内存机制详解_第3页
第3页 / 共35页
java内存机制详解_第4页
第4页 / 共35页
java内存机制详解_第5页
第5页 / 共35页
点击查看更多>>
资源描述

《java内存机制详解》由会员分享,可在线阅读,更多相关《java内存机制详解(35页珍藏版)》请在金锄头文库上搜索。

1、Java 内存机制详解 Java 堆(每个 Java 对象在其中分配)是您在编写 Java 应用程序时使用最频繁的内存区域。JVM 设计 用于将我们与主机的特性隔离,所以将内存当作堆来考虑再正常不过了。您一定遇到过 Java 堆 OutOfMemoryError , 它可能是由于对象泄漏造成的,也可能是因为堆的大小不足以存储所有数据, 您也可能了解这些场景的一些调试技巧。但是随着您的 Java 应用程序处理越来越多的数据和越来越多的 并发负载,您可能就会遇到无法使用常规技巧进行修复的 OutOfMemoryError 。 在一些场景中,即使 java 堆未满,也会抛出错误。当这类场景发生时,您

2、需要理解 Java 运行时环境(Java Runtime Environment,JRE)内部到底发生了什么。 Java 应用程序在 Java 运行时的虚拟化环境中运行,但是运行时本身是使用 C 之类的语言编写的本机程 序,它也会耗用本机资源,包括本机内存 。本机内存是可用于运行时进程的内存,它与 Java 应用程序使 用的 java 堆内存不同。每种虚拟化资源(包括 Java 堆和 Java 线程)都必须存储在本机内存中,虚拟机 在运行时使用的数据也是如此。这意味着主机的硬件和操作系统施加在本机内存上的限制会影响到 Java 应用程序的性能。 本系列文章共分两篇,讨论不同平台上的相应话题。本

3、文是其中一篇。在这两篇文章中,您将了解什么是 本机内存,Java 运行时如何使用它,本机内存耗尽之后会发生什么情况,以及如何调试本 机 OutOfMemoryError 。本文介绍 Windows 和 Linux 平台上的这一主题,不会介绍任何特定的运行时 实现。 本机内存简介 硬件限制 本机进程遇到的许多限制都是由硬件造成的,而与操作系统没有关系。每台计算机都有一个处理器和一些 随机存取存储器(RAM),后者也称为物理 内存。处理器将数据流解释为要执行的指令,它拥有一个或多 个处理单元,用于执行整数和浮点运算以及更高级的计算。处理器具有许多寄存器 常快速的内存元素, 用作被执行的计算的工作存

4、储,寄存器大小决定了一次计算可使用的最大数值。 处理器通过内存总线连接到物理内存。物理地址(处理器用于索引物理 RAM 的地址)的大小限制了可以 寻址的内存。例如,一个 16 位物理地址可以寻址 0x0000 到 0xFFFF 的内存地址,这个地址范围包括 216 = 65536 个惟一的内存位置。如果每个地址引用一个存储字节,那么一个 16 位物理地址将允许处 理器寻址 64KB 内存。 处理器被描述为特定数量的数据位。这通常指的是寄存器大小,但是也存在例外,比如 32 位 390 指的是 物理地址大小。对于桌面和服务器平台,这个数字为 31、32 或 64;对于嵌入式设备和微处理器,这个

5、数字可能小至 4。物理地址大小可以与寄存器带宽一样大,也可以比它大或小。如果在适当的操作系统上 运行,大部分 64 位处理器可以运行 32 位程序。 表 1 列出了一些流行的 Linux 和 Windows 架构,以及它们的寄存器和物理地址大小: 表 1. 一些流行处理器架构的寄存器和物理地址大小小 架构架构寄存器带宽(位)物理地址大小(位) (现代)Intel? x86 32 32 36,具有 物理地址扩展(Pentium Pro 和更高型号) x86 6464 目前为 48 位(以后将会增大) PPC6464 在 POWER 5 上为 50 位 390 31 位位3231 390 64 位

6、位6464 操作系统和虚拟内存 如果您编写无需操作系统,直接在处理器上运行的应用程序,您可以使用处理器可以寻址的所有内存(假 设连接到了足够的物理 RAM)。但是要使用多任务和硬件抽象等特性,几乎所有人都会使用某种类型的操 作系统来运行他们的程序。 在 Windows 和 Linux 等多任务操作系统中,有多个程序在使用系统资源。需要为每个程序分配物理内存 区域来在其中运行。可以设计这样一个操作系统:每个程序直接使用物理内存,并 且可以可靠地仅使用分 配给它的内存。一些嵌入式操作系统以这种方式工作,但是这在包含多个未经过集中测试的应用程序的环 境中是不切实际的,因为任何程序都 可能破坏其他程序

7、或者操作系统本身的内存。 虚拟内存 允许多个进程共享物理内存,而且不会破坏彼此的数据。在具有虚拟内存的操作系统(比如 Windows、Linux 和许多其他操作系统)中,每个程序都拥有自己的虚拟地址空间 一个逻辑地址区 域,其大小由该系统上的地址大小规定(所以,桌面和服务器平台的虚拟地址空间为 31、32 或 64 位)。 进程的虚拟地址空间中的区域可被映射到物理内存、文件或任何其他可寻址存储。当数据未使用时,操作 系统可以在物理内存与一个交换区域 (Windows 上的页面文件 或者 Linux 上的交换分区 )之间移动它, 以实现对物理内存的最佳利用率。当一个程序 尝试使用虚拟地址访问内存

8、时,操作系统连同片上硬件会将 该虚拟地址映射到物理位置,这个位置可以是物理 RAM、一个文件或页面文件/交换分区。如果一个内存 区域被移动到交换空间,那么它将在被使用之前加载回物理内存中。图 1 展示了虚拟内存如何将进程地址 空间区域映射到共享资源: 图 1. 虚拟内存将进程地址空间映射到物理资源 程序的每个实例以进程 的形式运行。在 Linux 和 Windows 上,进程是一个由受操作系统控制的资源 (比如文件和套接字信息)、一个典型的虚拟地址空间(在某些架构上不止一个)和至少一个执行线程构 成的集合。 虚拟地址空间大小可能比处理器的物理地址大小更小。32 位 Intel x86 最初拥有

9、的 32 位物理地址仅允 许处理器寻址 4GB 存储空间。后来,添加了一种称为物理地址扩展(Physical Address Extension, PAE)的特性,将物理地址大小扩大到了 36 位,允许安装或寻址至多 64GB RAM。PAE 允许操作系统 将 32 位的 4GB 虚拟地址空间映射到一个较大的物理地址范围,但是它不允许每个进程拥有 64GB 虚拟 地址空间。这意味着如果您将大于 4GB 的内存放入 32 位 Intel 服务器中,您将无法将所有内存直接映射 到一个单一进程中。 地址窗口扩展(Address Windowing Extension)特性允许 Windows 进程将

10、其 32 位地址空间的一部 分作为滑动窗口映射到较大的内存区域中。Linux 使用类似的技术将内存区域映射到虚拟地址空间中。这 意味着尽管您无法直接引用大于 4GB 的内存,但您仍然可以使用较大的内存区域。 内核空间和用户空间 尽管每个进程都有其自己的地址空间,但程序通常无法使用所有这些空间。地址空间被划分为用户空间 和 内核空间 。 内核是主要的操作系统程序,包含用于连接计算机硬件、调度程序以及提供联网和虚拟内存等 服务的逻辑。 作为计算机启动序列的一部分,操作系统内核运行并初始化硬件。一旦内核配置了硬件及其自己的内部状 态,第一个用户空间进程就会启动。如果用户 程序需要来自操作系统的服务,

11、它可以执行一种称为系统调 用 的操作与内核程序交互,内核程序然后执行该请求。系统调用通常是读取和写入文件、联网和启动新进 程等操作所必需的。 当执行系统调用时,内核需要访问其自己的内存和调用进程的内存。因为正在执行当前线程的处理器被配 置为使用地址空间映射来为当前进程映射虚拟 地址,所以大部分操作系统将每个进程地址空间的一部分映 射到一个通用的内核内存区域。被映射来供内核使用的地址空间部分称为内核空间,其余部分称为用户空 间,可供用户应用程序使用。 内核空间和用户空间之间的平衡关系因操作系统的不同而不同,甚至在运行于不同硬件架构之上的同一操 作系统的各个实例间也有所不同。这种平衡通 常是可配置

12、的,可进行调整来为用户应用程序或内核提供更 多空间。缩减内核区域可能导致一些问题,比如能够同时登录的用户数量限制或能够运行的进程数量限 制。 更小的用户空间意味着应用程序编程人员只能使用更少的内存空间。 默认情况下,32 位 Windows 拥有 2GB 用户空间和 2GB 内核空间。在一些 Windows 版本上,通过向 启动配置添加 /3GB 开关并使用 /LARGEADDRESSAWARE 开关重新链接应用程序,可以将这种平衡调 整为 3GB 用户空间和 1GB 内核空间。在 32 位 Linux 上,默认设置为 3GB 用户空间和 1GB 内核空间。 一些 Linux 分发版提供了一个

13、 hugemem 内核,支持 4GB 用户空间。为了实现这种配置,将进行系统 调用时使用的地址空间分配给内核。通过这种方式增加用户空间会减慢系统调用,因为每次进行系统调用 时,操作系统必 须在地址空间之间复制数据并重置进程地址-空间映射。图 2 展示了 32 位 Windows 的 地址-空间布局: 图 2. 32 位 Windows 的地址-空间布局 图 3 显示了 32 位 Linux 的地址-空间配置: 图 3. 32 位 Linux 的地址-空间布局 31 位 Linux 390 上还使用了一个独立的内核地址空间,其中较小的 2GB 地址空间使对单个地址空间进 行划分不太合理,但是,3

14、90 架构可以同时使用多个地址空间,而且不会降低性能。 进程空间必须包含程序需要的所有内容,包括程序本身和它使用的共享库(在 Windows 上为 DDL,在 Linux 上为 .so 文件)。共享库不仅会占据空间,使程序无法在其中存储数据,它们还会使地址空间碎片 化,减少可作为连续内存块分配的内存。这对于在拥有 3GB 用户空间的 Windows x86 上运行的程序尤 为明显。DLL 在构建时设置了首选的加载地址:当加载 DLL 时,它被映射到处于特定位置的地址空间, 除非该位置已经被占用,在这种情况下,它会加载到别处。Windows NT 最初设计时设置了 2GB 可用用 户空间,这对于

15、要构建来加载接近 2GB 区域的系统库很有用 使大部分用户区域都可供应用程序自由 使用。当用户区域扩展到 3GB 时,系统共享库仍然加载接近 2GB 数据(约为用户空间的一半)。尽管总 体用户空间为 3GB,但是不可能分配 3GB 大的内存块,因为共享库无法加载这么大的内存。 在 Windows 中使用 /3GB 开关,可以将内核空间减少一半,也就是最初设计的大小。在一些情形下,可 能耗尽 1GB 内核空间,使 I/O 变得缓慢,且无法正常创建新的用户会话。尽管 /3GB 开关可能对一些应 用程序非常有用,但任何使用它的环境在部署之前都应该进行彻底的负载测试。 本机内存泄漏或过度使用本机内存将

16、导致不同的问题,具体取决于您是耗尽了地址空间还是用完了物理内 存。耗尽地址空间通常只会发生在 32 位进程上,因为最大 4GB 的内存很容易分配完。64 位进程具有数 百或数千 GB 的用户空间,即使您特意消耗空间也很难耗尽这么大的空间。如果您确实耗尽了 Java 进程 的地址空间,那么 Java 运行时可能会出现一些陌生现象,本文稍后将详细讨论。当在进程地址空间比物 理内存大的系统上运行时,内存泄漏或过度使用本机内存会迫使操作系统交换后备存 储器来用作本机进程 的虚拟地址空间。访问经过交换的内存地址比读取驻留(在物理内存中)的地址慢得多,因为操作系统必 须从硬盘驱动器拉取数据。可能会分配 大量内存来用完所有物理内存和所有交换内存(页面空间),在 Linux 上,这将触发内核内存不足(OOM)结束程序,强制结束最消耗内存的进程。在 Windows 上,与 地址空间被占满时一样,内存分配将会失败。 同时,如果尝试使用比物理内存大的虚拟内存,显然在进程由于消耗内存太大而被结束之前就会遇到问题。 系统将变得异常缓慢,因为它会将大部分时 间用于在内存与交换空间之间来回复

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 电子/通信 > 综合/其它

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号