美文网首页
内存与性能

内存与性能

作者: 谭英智 | 来源:发表于2022-07-09 21:13 被阅读0次

申请与释放内存

申请内存的过程

  • 用户态使用malloc向操作系统申请内存
  • 操作系统查找页面是否有空闲内存,如果有则返回
  • 否则发生TLB缺页中断
  • 操作系统为进程挂载新页,并映射到一片空闲的物理内存
  • 操作系统从新页中,获取一片内存,并返回进程

直接裸用malloc,会让进程在不断的申请和释放内存,造成发生多次TLB中断,导致程序的性能下降

因此引入了内存池,伙伴系统和tcmalloc都是内存池的产物。

伙伴系统

通过对内存的大小分类,例如8字节的内存块,16字节的内存块,256字节的内存块

对不同类别的内存块,使用链表来管理。

当进程需要申请内存时,可以从最小满足的链表中选取一个内存块,来满足使用

tcmalloc

伙伴系统一般适用于单线程,如果是多线程,则需要加锁来管理,而锁的开销也是不容乐观的。

tcmalloc通过对每个线程管理独立的伙伴系统,并存在一个中央的伙伴系统。来减少在多线程场景下对锁的竞争

内存与磁盘

内存与磁盘息息相关

Page cache

内存与磁盘在数据写入和读取的时候,它们之间会使用缓冲和缓存来减少它们之间的速度差带来的影响。

缓冲和缓存也可以统称为Page cache。Page cache会定时定量的批量刷入磁盘,来提高性能。

如果系统内存变得紧张的时候,不仅仅会影响进程申请内存,还会导致写入磁盘和读取磁盘变慢,因为当系统内存紧张时,系统会自动的减少Page cache的大小,导致磁盘的读写变慢

fsync

fsync的作用是把page cache的脏页强制刷入磁盘,虽然fsync保证的数据可以实时落盘,但是这个api却会导致性能急剧下降。所以在设计方案时,fsync的使用是要慎重考虑的。

kafka在处理消息不丢的场景,并没有使用fsync,而是通过把消息成功同步给一个follower以上,则认为满足消息不丢,然后通过page cache,提高写入磁盘的性能

Swap 交换

在内存紧张时,操作系统会把不活跃的进程,从内存交换到磁盘,等到进程再次活跃时,再把进程交换回内存运行。

这对性能有极高要求的进程,swap是不允许的,如果把redis这样的进程,从内存和磁盘中换入换出,会造成redis的性能急剧下降,而达不到高并发的要求。

直接IO

数据从内存写入磁盘,可以不通过page cache,而是直接把内存写入磁盘。

这样带来的好处是,减少了一次内存拷贝,在高性能磁盘的场景,直接IO会是一个更优的方案

内存与内核

系统调用

当进程发生系统调用,进程会从用户态切换到内核态

寄存器信息,上下文信息,都会被保存和切换

这些切换在高性能场景下是要减少的。

优先使用性能高的系统API,优先使用异步API而不是同步API,优先使用批量调用而不是多次单独调用。

在选择操作系统方面,优先使用某些常用的系统API可以在用户态完成。

线程调度

操作系统是一般是多任务的,每个线程会轮番抢占CPU资源,在线程切换的过程中,内存的上下文需要被保存起来,以备线程再次唤醒时,线程可以继续运行。

相同的,这些上下文的切换,同样会带来性能的下降。

线程交互

原子变量

在多核CPU的架构下,每次原子变量的写入,都会在总线上对原子变量的地址进行上锁,直到写入的数据同步完成

可以看到,这种锁总线内存的做法,是会对性能造成一些轻微的影响的

自旋锁

自旋锁使用了原子变量,所以对总线内存上锁是会对性能带来影响

其次,自旋锁会使用CPU阑珊,这会带来进一步的性能影响

互斥锁

互斥锁也使用了原子变量,因此它对总线内存上锁也会对性能带来影响

其次,当它抢不到资源的时候,线程会陷入休眠

休眠会带来上下文切换,会对性能带来进一步的影响

零拷贝

如果一个进程需要把文件的数据发送到网络,进程通过系统api read获取文件的内容到内存,再把内容从内存发送到网络,会导致文件的内容发生多次拷贝

操作系统提供零拷贝API,把读取文件和发送到网络,内容不需要拷贝到用户态,在内核态就可以直接完成。

实现零拷贝的功能,来提升性能。

页表

如果有两个线程,他们各自有两个变量,而这两个变量分贝在两个不同的页表

当线程轮番频繁的操作这两个变量的时候,会导致线程读取的页表切来切去

因此在申请内存时,尽量同一个页表的内存,只给一个线程使用

内存与CPU

普通变量

普通变量,编译器可以把变量放入寄存器中,来实现极致的性能

volatile变量

volatile变量,CPU每次读取都需要在高速缓存的读取,而不能优化成从寄存器读取,导致性能有一定下降

原子变量

原子操作是通过锁总线内存来达到的

高速缓存与主存

局部性和顺序性

在写程序时,需要考虑数据的局部性和顺序性,减少相同的数据块在内存和高速缓存之间的交换次数。

来达到高性能的目的。

相关文章

网友评论

      本文标题:内存与性能

      本文链接:https://www.haomeiwen.com/subject/ybrgertx.html