swap是Linux的一种内存管理机制,为了避免由于物理内存不足造成的OOM,在物理内存不足的时候,操作系统会将物理内存中一部分空间释放出来,这部分空间中的内容移动到磁盘中,释放出来的空间分配给需要内存的进程使用。
哪部分物理内存中的内容需要移动出来,这个系统有一定的机制,没有非常详细的研究过,不过感觉很少被使用的内存应该会优先进行swap。
Linux进行内存分配的时候不是直接分配物理内存,而是分配虚拟内存空间给进程,进程运行的时候,随着需要存储的对象的增多,系统会开辟更多物理内存给进程使用。
Linux服务器上运行JAVA服务的时候,首先启动的是JVM,jvm本质上是一个c写的程序,启动的时候,系统本身会为jvm分配内存。只不过对于用户来说,并不关心jvm本身占用的内存,而最多关心的是jvm管理的堆内存空间,这部分空间大大小可以通过-Xmx&-Xms
进行设置。
上面提到linux为进程分配的内存是虚拟内存,真正使用的时候才回去分配物理内存,所以我们通过上面的-Xms
设置最小堆大小的时候,假设1G,查看进程占用的内存会发现,刚开始启动的时候,内存并没有占用到1G,这也有效的说明了,linux为jvm分配的内存是虚拟内存,不过对于jvm来说,可以通过参数-XX:+AlwaysPreTouch
,让jvm分配的堆内存真正分配到物理内存中,配置-XX:+AlwaysPreTouch
参数后,JVM将-Xms
指定的堆内存中每个字节都写入’0’,这样的话,除了在虚拟内存中以内部数据结构保留之外,还会在物理内存中分配。
swap对jvm内存回收的影响
上面提到,java进程运行的时候,虽然内存占用主要是在堆内存,但是实际上是不止这些的,包括:栈内存、方法区内存、jvm本身运行需要的内存、程序运行过程中使用的堆外内存;系统运行过程中,还会为文件系统的buffer开辟内存、网络传输的buffer开辟内存缓存等。
所以经常会发现,我们一台8G的机器,运行一个java进程,堆内存分配4G,最终java进程占用的内存超过4G,并且系统已经开始进行swap。
swap对于jvm的垃圾回收的影响还是很严重的,因为内存中的数据是被交换到了磁盘,那么这部分数据再次被读取的时候,需要从磁盘读取加载到内存中,这个速度是很慢的。
想像这样一种场景:
犹豫系统内存不足,进行swap操作,将jvm堆内存中的部分冷数据swap到了磁盘中,后续进行垃圾回收的时候,jvm需要回收被swap的这部分内存,那么jvm需要将磁盘中的数据加载到内存,这个过程很慢,更严重的,很有此时物理内存不足以加载被swap到磁盘中的这部分数据,系统又将jvm另一部分内存swap到磁盘,释放物理内存,后续jvm回收那部分内存的时候,又需要去磁盘中进行加载,整个gc的速度会慢非常多,甚至导致进程对外无响应了。
所以说当系统swap内存较多的时候,需要提高警惕,分析当前程序是否有滥用内存的情况,如果程序设计正常,那么需要考虑增加机器的内存了。