理解 JVM 如何使用 Windows 和 Linux 上的本机内存(1)本机内存简介-2
- UID
- 1066743
|
理解 JVM 如何使用 Windows 和 Linux 上的本机内存(1)本机内存简介-2
内核空间和用户空间尽管每个进程都有其自己的地址空间,但程序通常无法使用所有这些空间。地址空间被划分为用户空间 和内核空间。内核是主要的操作系统程序,包含用于连接计算机硬件、调度程序以及提供联网和虚拟内存等服务的逻辑。
作为计算机启动序列的一部分,操作系统内核运行并初始化硬件。一旦内核配置了硬件及其自己的内部状态,第一个用户空间进程就会启动。如果用户程序需要来自操作系统的服务,它可以执行一种称为系统调用 的操作与内核程序交互,内核程序然后执行该请求。系统调用通常是读取和写入文件、联网和启动新进程等操作所必需的。
当执行系统调用时,内核需要访问其自己的内存和调用进程的内存。因为正在执行当前线程的处理器被配置为使用地址空间映射来为当前进程映射虚拟地址,所以大部分操作系统将每个进程地址空间的一部分映射到一个通用的内核内存区域。被映射来供内核使用的地址空间部分称为内核空间,其余部分称为用户空间,可供用户应用程序使用。
内核空间和用户空间之间的平衡关系因操作系统的不同而不同,甚至在运行于不同硬件架构之上的同一操作系统的各个实例间也有所不同。这种平衡通常是可配置的,可进行调整来为用户应用程序或内核提供更多空间。缩减内核区域可能导致一些问题,比如能够同时登录的用户数量限制或能够运行的进程数量限制。更小的用户空间意味着应用程序编程人员只能使用更少的内存空间。
默认情况下,32 位 Windows 拥有 2GB 用户空间和 2GB 内核空间。在一些 Windows 版本上,通过向启动配置添加 /3GB 开关并使用 /LARGEADDRESSAWARE 开关重新链接应用程序,可以将这种平衡调整为 3GB 用户空间和 1GB 内核空间。在 32 位 Linux 上,默认设置为 3GB 用户空间和 1GB 内核空间。一些 Linux 分发版提供了一个 hugemem 内核,支持 4GB 用户空间。为了实现这种配置,将进行系统调用时使用的地址空间分配给内核。通过这种方式增加用户空间会减慢系统调用,因为每次进行系统调用时,操作系统必须在地址空间之间复制数据并重置进程地址-空间映射。图 2 展示了 32 位 Windows 的地址-空间布局:
图 2. 32 位 Windows 的地址-空间布局图 3 显示了 32 位 Linux 的地址-空间配置:
图 3. 32 位 Linux 的地址-空间布局31 位 Linux 390 上还使用了一个独立的内核地址空间,其中较小的 2GB 地址空间使对单个地址空间进行划分不太合理,但是,390 架构可以同时使用多个地址空间,而且不会降低性能。
进程空间必须包含程序需要的所有内容,包括程序本身和它使用的共享库(在 Windows 上为 DDL,在 Linux 上为 .so 文件)。共享库不仅会占据空间,使程序无法在其中存储数据,它们还会使地址空间碎片化,减少可作为连续内存块分配的内存。这对于在拥有 3GB 用户空间的 Windows x86 上运行的程序尤为明显。DLL 在构建时设置了首选的加载地址:当加载 DLL 时,它被映射到处于特定位置的地址空间,除非该位置已经被占用,在这种情况下,它会加载到别处。Windows NT 最初设计时设置了 2GB 可用用户空间,这对于要构建来加载接近 2GB 区域的系统库很有用 —— 使大部分用户区域都可供应用程序自由使用。当用户区域扩展到 3GB 时,系统共享库仍然加载接近 2GB 数据(约为用户空间的一半)。尽管总体用户空间为 3GB,但是不可能分配 3GB 大的内存块,因为共享库无法加载这么大的内存。
在 Windows 中使用 /3GB 开关,可以将内核空间减少一半,也就是最初设计的大小。在一些情形下,可能耗尽 1GB 内核空间,使 I/O 变得缓慢,且无法正常创建新的用户会话。尽管 /3GB 开关可能对一些应用程序非常有用,但任何使用它的环境在部署之前都应该进行彻底的负载测试。参见 ,获取关于 /3GB 开关及其优缺点的更多信息的链接。
本机内存泄漏或过度使用本机内存将导致不同的问题,具体取决于您是耗尽了地址空间还是用完了物理内存。耗尽地址空间通常只会发生在 32 位进程上,因为最大 4GB 的内存很容易分配完。64 位进程具有数百或数千 GB 的用户空间,即使您特意消耗空间也很难耗尽这么大的空间。如果您确实耗尽了 Java 进程的地址空间,那么 Java 运行时可能会出现一些陌生现象,本文稍后将详细讨论。当在进程地址空间比物理内存大的系统上运行时,内存泄漏或过度使用本机内存会迫使操作系统交换后备存储器来用作本机进程的虚拟地址空间。访问经过交换的内存地址比读取驻留(在物理内存中)的地址慢得多,因为操作系统必须从硬盘驱动器拉取数据。可能会分配大量内存来用完所有物理内存和所有交换内存(页面空间),在 Linux 上,这将触发内核内存不足(OOM)结束程序,强制结束最消耗内存的进程。在 Windows 上,与地址空间被占满时一样,内存分配将会失败。
同时,如果尝试使用比物理内存大的虚拟内存,显然在进程由于消耗内存太大而被结束之前就会遇到问题。系统将变得异常缓慢,因为它会将大部分时间用于在内存与交换空间之间来回复制数据。当发生这种情况时,计算机和独立应用程序的性能将变得非常糟糕,从而使用户意识到出现了问题。当 JVM 的 Java 堆被交换出来时,垃圾收集器的性能会变得非常差,应用程序可能被挂起。如果一台机器上同时使用了多个 Java 运行时,那么物理内存必须足够分配给所有 Java 堆。 |
|
|
|
|
|