在计算机的组件中,内存是非常重要的存在。在做性能测试的过程中,针对内存的监控也是非常核心的一类指标项。在一些场景的沟通中,发现大家对于内存的理解可能存在一些偏差。本文结合笔者的经验,对内存做一些基础知识的汇总。
为什么会有内存的存在?
在冯.诺依曼结构的核心设计思想中,计算机的五个基本组成部分:运算器、控制器、存储器、输入设备、输出设备。其中的存储器指主要功能是存储程序和各种数据,并且能够在计算机运行过程高速、自动地完成程序或者数据的存储。存储器可以分为内部存储器(内存)和外部存储器(硬盘)。
早期的内存是固化在主板上,可存储的数据有限。随着 CPU 的工艺技术不断发展,速度越来越快(I7 的 CPU,主频可达到 2.69GHz)),但是硬盘由于机械结构的局限性(读写速度 120MB/S),无法跟上 CPU 的节奏,从而造成 CPU 资源的闲置。于是就有的独立的内存(读写速度大约在 7~9GB/s),用于把常用数据从硬盘中读取出来(Cached ),供 CPU 快速使用,同时,把经 CPU 处理过的数据暂存在内存中(Buffers),后续再固化到硬盘中。
这个过程是不是很像我们现在的 业务 —> redis —> 数据库的结构。
如上图所示,不同操作系统对于内存的管理机制也是不一样的。简单来说,Windows 对于内存的管理就是省着用,而对于 Lixnu 来说,就是能用多少就用多少,尽可能用。
在性能测试过程中,我们对于 Linux 操作系统的内存查看,一般会通过 Free 命令来看,如下图所示,在算可用内存的时候,是 free+buff/cache,而不单单只看 free 的值。因为 buff/cache 在需要的时候,可以快速被释放,变成内存使用。也可以通过命令来手动释放这类内存。
echo 3 >proc/sys/vm/drop_caches
那么,在 Linxu 中,内存什么时候真的不够用了呢?就是 Swap 有值了,Swap 指的是硬盘上交换分区的使用大小。设计的目的就是当上面提到的 +buffers/cache 表示的可用内存都已使用完,新的读写请求过来后,会把内存中的部分数据写入磁盘,从而把磁盘的部分空间当作虚拟内存来使用。
那我们通常所说的内存泄漏又指的是什么呢?
内存泄漏一般指的是某个对象的引用丢失,无法再访问到该引用,但是该引用却依旧引用着某个对象,导致这个对象无法回收,最终导致内存溢出 OOM。简单而言,就是内存里的对象无法被引用,也无法被回收,一直占用着不释放,导致内存的可使用量减少。在面试过程中,如果没有特别说明,内存泄漏指的是 JVM 内存的泄露(JAVA 是当下企业的主流研发语言,所以一般情况下探讨的是这类问题,其他语言当然也存在,但是相对来说没那么严重,原因是其他语言都是直接使用物理内存,量比较大,而 JAVA 使用的是 JVM 内存,一般都只会设置在 2G 左右,过高会严重影响 GC 效率,导致服务不可用)。
那么,如何判断 JVM 是否存在泄露呢?目前主流的工具(Visualvm、jstack、Jprofiler 等)都会提供相对应的功能,在发生 GC 的时候,如果发现每次 GC 的量在不断地变小,且 GC 的频率越来越快,那么就有可能是内存泄露了。这个时候就需要去看看 JVM 里存放了哪些大对象。上面提到的工具都可以查看,具体的工具使用,可自行百度。
对于测试的同学,不管是专注于哪类测试,对于计算机的工作原理都需要有一定的了解,基础需要打牢固。
留几个小问题,供大家思考:
程序从编译到被 CPU 处理,会经过哪些步骤?
通过网络接口传输的数据,是直接被 CPU 处理,还是先到内存或者硬盘?
性能圈流行一句话叫一切问题皆 IO,是不是有道理的?原理是什么呢?