JVM和Linux之间的详细内存关系

在一些具有8g物理内存的服务器上,主要运行Java服务。系统内存分配如下:Java服务的JVM堆大小设置为6g,监视过程大约需要600m,Linux本身使用大约800m。

从表面上看,物理记忆应该足够;但实际操作是会发生大量SWAP(表明物理内存不足),如下图所示。由于同时发生SWAP和GC会导致JVM严重卡住,我们不得不问:内存在哪里?

JVM和Linux之间的详细内存关系

JVM和Linux之间的详细内存关系

要分析此问题,了解JVM与操作系统之间的内存关系非常重要。下一步是对Linux和JVM之间的内存关系进行一些分析。

首先,Linux和进程内存模型

JVM作为Linux系统上的进程运行。了解Linux和进程之间的内存关系是理解JVM和Linux内存之间关系的基础。下图显示了硬件,系统和进程级别的内存之间的摘要关系。

JVM和Linux之间的详细内存关系

从硬件角度来看,Linux系统的内存空间由两部分组成:物理内存和SWAP(在磁盘上)。物理内存是Linux活动使用的主要内存区域;当物理内存不足时,Linux会将一些未使用的内存数据放入磁盘上的SWAP中,以释放更多可用内存空间;使用位于SWAP中的数据时,必须先将其交换回内存。有关JVM运行时区域的详细说明,我建议大家看一下。

从Linux系统来看,除了引导系统的BIN区域外,整个内存空间主要分为两部分:内核内存(Kernel space),用户内存(User space)。

内核内存是Linux本身使用的内存空间。它主要用于程序逻辑,例如程序调度,内存分配和连接硬件资源。

用户内存提供给每个进程的主空间,Linux为每个进程提供相同的虚拟内存空间;这使得这些过程彼此独立,并且不会相互干扰。实现方法是使用虚拟内存技术:为每个进程提供虚拟内存空间,仅在实际使用虚拟内存时分配物理内存。如下图所示,对于32位的Linux系统,0到3G的虚拟内存空间分配通常用作用户空间,3到4G的虚拟内存空间分配为内核空间; 64位系统的划分是类似的。 。

JVM和Linux之间的详细内存关系

从过程的角度来看,进程可以直接访问的用户存储器(虚拟存储空间)分为五个部分:代码区,数据区,堆区,堆栈区和未使用区。

应用程序的机器代码代码存储在代码区域中。代码在运行过程中无法修改,具有只读和固定大小的特征。

数据区存储应用程序中的全局数据,静态数据和一些常量字符串等,其大小也是固定的。

堆是动态应用运行时程序的空间,属于程序运行时直接应用和释放的内存资源。

堆栈区域用于存储传入参数,临时变量和返回地址等数据。

未使用区域是用于分配新存储空间的备用区域。

第二,进程和JVM内存空间

JVM本质上是一个进程,因此它的内存空间(也称为运行时数据区,注意JMM之间的差异)也具有该进程的一般特征。在Java中深入解释JVM内存管理,这个参考。

但是,JVM不是一个普通的进程,它在内存空间中有许多新功能。主要有两个原因:

1. JVM将属于操作系统管理范围的许多东西移植到JVM,以减少系统调用的次数;

2. Java NIO,目的是减少读写IO系统调用的开销。将JVM进程与正常进程内存模型进行比较,如下所示。:

JVM和Linux之间的详细内存关系

应该注意的是,该模型不是JVM内存使用的准确模型,而是从操作系统的角度关注JVM的内部细节(尽管很重要)。下面从两个方面描述JVM进程的内存特征:用户内存和内核内存。

用户记忆

上图突出显示了JVM进程模型的代码区和数据区是指JVM本身,而不是Java程序。正常的进程堆栈区域通常仅用作JVM中的线程堆栈。 JVM堆区域和正常进程之间的差异是最大的,详情如下:

第一个是永久性的一代。永久生成本质上是Java程序的代码和数据区域。 Java程序中的类被加载到整个区域的不同数据结构中,包括常量池,字段,方法数据,方法体,构造函数以及类中的专用方法,实例初始化和接口初始化。该区域是操作系统堆的一部分;对于Java程序,这是容纳程序本身和静态资源的空间,允许JVM解释Java程序的执行。其次是新一代和老年。新一代和老一代是Java程序实际使用的堆空间,主要用于存储对象的存储;但管理方法与普通流程有本质区别。

当正常进程在运行时向内存对象分配空间时,例如,当C ++执行新操作时,它会触发分配内存空间的系统调用,并且操作系统的线程根据对象的大小分配空间,回报;同时,当程序释放对象时例如,当C ++执行删除操作时,它还会触发系统调用,以通知操作系统对象可以回收操作系统对象占用的空间。

JVM对内存的使用与一般过程不同。 JVM将一个完整的内存区域(特定的大小可以在JVM参数中调整)作为一堆Java程序(分为新一代和老一代)应用于操作系统;当Java程序申请内存空间时,例如执行新操作,JVM将在这里。段空间根据所需大小分配给Java程序,并且Java程序不负责在释放对象空间时通知JVM。垃圾对象内存空间由JVM回收。

JVM内存管理方法的优点是显而易见的,包括:首先,减少系统调用的数量,JVM在为Java程序分配内存空间时不需要操作系统干预,只需要向操作系统申请内存当Java堆大小更改时。或者通知回收,每次分配和回收内存空间时,正常程序需要系统调用才能参与;二,减少内存泄漏,正常程序没有(或不及时)通知释放操作系统内存空间是内存泄漏的重要原因之一。并且由JVM管理,可以避免程序员造成的内存泄漏。

最后,有一个未使用的区域,这是一个用于分配新内存空间的备用区域。对于正常进程,此区域可用于堆和堆栈空间请求和释放。该区域用于每个堆内存分配,因此大小经常变化;对于JVM进程,使用堆大小和线程堆栈。这个区域虽然堆大小一般调整较少,所以尺寸相对稳定。操作系统动态调整此区域的大小,并且此区域通常不分配实际物理内存,只允许进程在此区域中应用堆或堆栈空间。

2.内核内存

应用程序通常不直接处理内核内存,内核内存由操作系统管理和使用;然而,由于Linux专注于性能和改进,新功能允许应用程序使用内核内存或映射到内核空间。 Java NIO就是在这种背景下诞生的,它充分利用了Linux系统的新特性,提高了Java程序的IO性能。JVM和Linux之间的详细内存关系

上图显示了Java NIO在Linux系统中使用的内核内存的分布。 Nio缓冲区主要包括:nio在使用各种通道时使用的ByteBuffer,Java程序主动使用ByteBuffer.allocateDirector来申请分配的Buffer。

在PageCache中,nio使用的内存主要包括:FileChannel.map模式打开文件占用映射所需的Cache,FileChannel.transferTo和FileChannel.transferFrom(图中未显示)。

可以通过JMX监视NIO Buffer和映射的使用,如下图所示。但是,FileChannel的实现是通过系统调用使用本机PageCache。该过程对Java是透明的,无法监视这部分内存的使用情况。

JVM和Linux之间的详细内存关系

Linux和Java NIO为程序打开内核内存空间,主要是为了减少不必要的复制,以减少IO操作系统调用的开销。例如,使用常规方法和NIO将数据从磁盘文件发送到网卡时,将比较数据流,如下图所示:

JVM和Linux之间的详细内存关系

在内核内存和用户内存之间复制数据是浪费资源和时间。从上图中,我们可以看到NIO方法减少了内核内存和用户内存之间的数据副本两次。这是Java NIO高性能的重要机制之一(另一种是异步非阻塞)。

从上面可以看出,内核内存对Java程序性能也非常重要。因此,在划分系统内存使用时,必须为内核留出一些空闲空间。

三,案例分析

1.内存分配问题

通过以上分析,省略较小的区域,可以总结JVM占用的内存:

JVM内存≈Java永久代+ Java堆(新一代和老一代)+线程堆栈+ Java NIO

回到本文开头提出的问题,原来的内存分配是:6g(java堆)+ 600m(监控)+ 800m(系统),剩下的600m内存未分配。

现在分析这个600m内存的分配:

Linux保留了大约200米,这是Linux正常运行的必要条件。

Java服务的线程数为160.JVM的默认线程堆栈大小为1m,因此使用160m内存。Java NIO缓冲区,JMX最长可达200米。

Java服务使用NIO大量读写文件,您需要使用PageCache。如前面的分析所述,这不是一个好的定量估计。

前三项总计达560米,因此您可以得出Linux物理内存不足的结论。

细心的人会发现这两个服务器在介绍中给出。一个SWAP最多占用2.16g,另一个SWAP占用871m。然而,似乎我们的记忆差距并不大。实际上,这是由于同时实施SWAP和GC。从下图中可以看出,SWAP的使用与长期GC同时发生。

JVM和Linux之间的详细内存关系

JVM和Linux之间的详细内存关系

SWAP和GC的同时发生将导致GC时间长,严重的JVM以及极端的服务崩溃。原因如下:当JVM执行GC时,需要遍历相应堆分区的已用内存;如果GC,堆的某些部分交换到SWAP,并且在遍历到此部分时需要将其交换回内存。同时,由于内存空间不足,有必要将内存中堆的另一部分切换为SWAP;在遍历堆分区的过程中,(在极端情况下)整个堆分区将依次写入SWAP。 Linux对SWAP的恢复滞后,我们将看到很多SWAP用法。可以通过减小堆大小或增加物理内存来解决上述问题。

因此,我们得出结论,部署Java服务的Linux系统需要避免在内存分配中使用SWAP;如何分配它取决于JVM for Java permanent generation和Java heap(新一代和老一代)在不同的场景中。 ,线程堆栈和Java NIO的内存使用情况。

2.内存泄漏问题

另一种情况是8g内存服务器,Linux使用800m,监控进程使用600m,堆大小设置为4g;系统可用内存约为2.5g,但很多SWAP也被占用。

对此问题的分析如下:

1在这种情况下,Java永久生成,Java堆(新一代和老一代),线程堆栈使用的内存基本上是固定的,因此占用过多内存的原因位于Java NIO上。

2根据以前的模型,Java NIO使用的内存主要分布在Linux内核内存的System区域和PageCache区域。查看监控记录,如下图所示,我们可以看到在SWAP发生之前,也就是说,当物理内存不足时,PageCache会急剧缩小。因此,位于系统区域的Java NIO缓冲区中可能会发生内存泄漏。JVM和Linux之间的详细内存关系

JVM和Linux之间的详细内存关系

3由于NIO的DirectByteBuffer需要稍后在GC中回收,因此连续申请DirectByteBuffer的程序通常需要调用System.gc()以避免FullGC长期失效导致旧区域中的DirectByteBuffer内存泄漏。在分析了这一点之后,可以推断出有两个可能的原因:首先,Java程序在必要时不调用System.gc();第二,System.gc()被禁用。

4最后,有必要检查JVM启动参数和Java程序的DirectByteBuffer用法。在此示例中,查看JVM启动参数并发现启用-XX: + DisableExplicitGC会导致System.gc()被禁用。

上一篇: 没有了

下一篇: 没有了

分享到:

Java 内存 关系_JVM和Linux之间的详细内存关系相关推荐

  1. linux 内存清理 释放命令,Linux系统中的内存清理和释放命令总结

    Linux内核代码量大.逻辑关系复杂,因此对内核中的错误进行追溯和调试一直以来都是一件既耗费时间又耗费精力的事情.接下来是小编为大家收集的Linux系统中的内存清理和释放命令总结,希望能帮到大家. L ...

  2. linux查看进程的内存使用情况,[转]linux下查看进程内存使用情况

    动态查看一个进程的内存使用 1.top命令 top -d 1 -p pid [,pid ...] //设置为delay 1s,默认是delay 3s 如果想根据内存使用量进行排序,可以shift + ...

  3. linux查服务器总内存大小,怎么查看linux中的可用内存大小

    怎么查看linux中的可用内存大小 发布时间:2020-06-16 13:28:33 来源:亿速云 阅读:620 作者:鸽子 作为Linux用户,特别是管理员,我们需要检查系统使用多少内存资源以及有多 ...

  4. linux 内存显示多少g,Linux以GB显示内存大小

    Linux以GB显示内存大小 [email protected]:~$ free -g total used free shared buffers cached Mem: 2 1 1 0 0 0 - ...

  5. linux查看主板最大内存容量,Linux下查看内存插槽数、最大...-linux下手动清理内存或缓存的...-查看linux主板内存槽与内存信息的方法详解_169IT.COM...

    一.先来看几个用dmidecode查看内存信息的例子. 1.查看内存槽数.那个槽位插了内存,大小是多少 代码示例: dmidecode|grep -P -A5 "Memory\s+Devic ...

  6. linux 清理内存的c函数,Linux C函数之内存配置函数

    1. 配置和释放内存 alloca: 配置内存空间 头文件: stdlib.h 函数定义: void *alloc(size_t size); 说明: alloca()用来配置size个字节的内存空间 ...

  7. linux和unix有什么关系,Unix 与 Linux 之间是什么关系?

    摘要 如果想了解 Linux 的诞生和发展,推荐看一下 Linus Torvalds 的自传<只是为了好玩>.这是以 Linux 创始人的角度讲的 Linux 的诞生和发展,非常有参考意义 ...

  8. linux 内存交换参数,Ubuntu Linux:处理交换内存和内存使用情况

    我的Ubuntu比任务管理器显示的内存更多: sudo ps -e --format rss | awk 'BEGIN{c=0} {c+=$1} END{print c/1024}' 2750.29 ...

  9. linux共享内存的定义,共享内存是什么意思 Linux系统如何共享内存

    共享内存概念 共享内存是通信效率最高的IPC方式,因为进程可以直接读写内存,而无需进行数据的拷备.但是它没有自带同步机制,需要配合信号量等方式来进行同步. 共享内存被创建以后,同一块物理内存被映射到了 ...

最新文章

  1. windows下的sysprep
  2. 动态修改属性设置 easyUI
  3. eBay Notification介绍
  4. how is SAP OData count implemented in the backend
  5. 彻底理解python递归_Python开发之-Python递归图示理解
  6. nc 结合htc hts 反弹shell(内网代理环境下)
  7. Tomcat,Jboss,Weblogic通过jndi连接数据库
  8. Linux 文件权限、用户权限和用户组管理vim的一些基本使用技巧
  9. 安装完jdk在cmd输入Java没有反应的解决办法
  10. [C++ Quiz] Intermediate level
  11. JAVA8免费下载安装(win10)
  12. 数据库可视化软件 安装 for windows
  13. 开源许可证 有人管吗_4个令人困惑的开源许可证场景以及如何浏览它们
  14. VC++制作连连看辅助经验分享
  15. 三维图看法亲身经验.
  16. 老李分享:《Java Performance》笔记2——JVM命令行选项及垃圾收集日志解析 2
  17. Android Studio记录一个错误:解析软件包时出现问题
  18. Python 无监督学习实用指南:1~5
  19. 马德里的Uber司机
  20. IP地址的分类及子网掩码的计算

热门文章

  1. redis集群的搭建详细教程
  2. windows 启动停止 java进程
  3. 日志模块-logging模块
  4. 【代码笔记】iOS-自定义loading(IanAlert)
  5. 基于类的命令行notebook的实现
  6. 莫侵残日噪,正在异乡听
  7. javascript中浅拷贝和深拷贝的理解
  8. http://www.shengshiyouxi.com
  9. 区分关联、依赖和聚集关系
  10. linux——线程(1)