您当前的位置:首页 > 电脑百科 > 软件技术 > 操作系统 > linux百科

linux中申请内存的情况分析

时间:2022-07-12 15:25:06  来源:  作者:码农世界

一 前言

内存对于系统资源来说,非常重要,内存问题可以导致系统延迟增大,系统内存泄漏,进程被kill等多种严重问题,所以分析进程的内存占用很有必要。本文重点分析了程序中动态申请内存的情况。

注意所有测试是 5.13.0-52内核条件下测试的,不同的内核测试环境,内存分类会有很大的不同。

二 程序内存结构

linux 32位系统中默认虚拟的内存布局如下:

linux中申请内存的情况分析

 

说明:

在linux中每个进程都有各自的虚拟内存空间,空间的大小和cpu的位数决定了虚拟空间的上限,比如在32位系统下,硬件可以访问的内存空间上限是4GB,这4GB的空间也不是完全可以给应用程序使用。

整个内存空间分为两个部分,操作系统占用一部分,从地址0xC0000000到0xFFFFFFFF这1GB的空间。剩下的从0x00000000到0xBFFFFFFF共3GB空间共3GB空间;

ELF可执行文件将整个虚拟内存空间分为多个segment;

操作系统是通过VMA 对进程的虚拟内存空间进行管理的。

VMA 是virtual Memory Area的简称,一个简单的程序VMA展示如下:

root@ubuntu-lab:/sys/kernel/debug/tracing# cat /proc/9776/maps
5655a000-5655b000 r--p 00000000 fd:00 1193979                            /home/miao/c-test/mm-test/a.out
5655b000-5655c000 r-xp 00001000 fd:00 1193979                            /home/miao/c-test/mm-test/a.out
5655c000-5655d000 r--p 00002000 fd:00 1193979                            /home/miao/c-test/mm-test/a.out
5655d000-5655e000 r--p 00002000 fd:00 1193979                            /home/miao/c-test/mm-test/a.out
5655e000-5655f000 rw-p 00003000 fd:00 1193979                            /home/miao/c-test/mm-test/a.out
5746c000-5748e000 rw-p 00000000 00:00 0                                  [heap]
f7d83000-f7da3000 r--p 00000000 fd:00 546008                             /usr/lib32/libc.so.6
f7da3000-f7f1f000 r-xp 00020000 fd:00 546008                             /usr/lib32/libc.so.6
f7f1f000-f7fa4000 r--p 0019c000 fd:00 546008                             /usr/lib32/libc.so.6
f7fa4000-f7fa5000 ---p 00221000 fd:00 546008                             /usr/lib32/libc.so.6
f7fa5000-f7fa7000 r--p 00221000 fd:00 546008                             /usr/lib32/libc.so.6
f7fa7000-f7fa8000 rw-p 00223000 fd:00 546008                             /usr/lib32/libc.so.6
f7fa8000-f7fb2000 rw-p 00000000 00:00 0 
f7fbc000-f7fbe000 rw-p 00000000 00:00 0 
f7fbe000-f7fc2000 r--p 00000000 00:00 0                                  [vvar]
f7fc2000-f7fc4000 r-xp 00000000 00:00 0                                  [vdso]
f7fc4000-f7fc5000 r--p 00000000 fd:00 546004                             /usr/lib32/ld-linux.so.2
f7fc5000-f7fe8000 r-xp 00001000 fd:00 546004                             /usr/lib32/ld-linux.so.2
f7fe8000-f7ff5000 r--p 00024000 fd:00 546004                             /usr/lib32/ld-linux.so.2
f7ff6000-f7ff8000 r--p 00031000 fd:00 546004                             /usr/lib32/ld-linux.so.2
f7ff8000-f7ff9000 rw-p 00033000 fd:00 546004                             /usr/lib32/ld-linux.so.2
ffe18000-ffe39000 rw-p 00000000 00:00 0                                  [stack]

说明:

  1. 第一列VMA的地址范围;(虚拟地址)
  2. 第二列VMA的权限,r标识可读,w标识可写,x标识可执行,p 标识私有,s标识共享;
  3. 第三列偏移,表示VMA对应的Segment在映像文件中的便宜;
  4. 第四列一般表示映像文件所在设备的主设备号:次设备号,这里面主设备号大多显示为fd,难道是一个原因?非文件映射的内存,比如堆和栈,则这两位显示为00:00
  5. 第五列 标识映射文件的节点号;
  6. 第六列标识映射的具体文件,可以看到除了程序文件外,还有使用的库的文件信息。 vdso 为特殊的VMA,用于和内核进行交互。

采用的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


int g_int = 123;

static g_static_int2 = 456;
static g_static_int_not_init;


int mAIn(void)
{
  int l_int = 3;
  int l_int2 = 4;

  static l_static_int =6;
  static l_static_int2;


  int * pint = (int*)malloc(sizeof(int));
  *pint = 12;

  printf("g_int:%d,tg_static_int2:%d tg_static_int_not_init:%d n",g_int,g_static_int2,g_static_int_not_init);
  printf("g_int:%p,tg_static_int2:%p tg_static_int_not_init:%p n",&g_int,&g_static_int2,&g_static_int_not_init);
  
  printf("l_int:%d tl_int2:%d tl_static_int:%d,tl_static_int2:%d,tpint:%dn",l_int,l_int2,l_static_int,l_static_int2,*pint);
  printf("l_int:%p tl_int2:%p tl_static_int:%p,tl_static_int2:%p,tpint:%pn",&l_int,&l_int2,&l_static_int,&l_static_int2,pint);
  while(1) {
    sleep(3);
    printf("PID:%dn",getpid());
  }
  free(pint);
  return 0;
}

多次运行可以发现我们变量的地址在其应该对应的空间内,同时发现每次堆和stack的地址是每次不同的,这也是为了安全期间,设置的随机偏移。

顺便说下stack为主线程的栈,最大的大小默认是ulimit -s ,一般为8MB,pthread_create 创建的栈大小一般为2MB,不同架构不同而且和ulimit 设置的大小有关,也可以自行更改。

三 计算程序内存大小

至于程序内存使用大小,比较简单的方法是top -p pid 直接看到如下:

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                            
  12375 miao      20   0    2764    852    788 S   0.0   0.0   0:00.00 a.out                                              

VIRT即虚拟内存大小,RES即实际内存大小,这两个一般最重要,就够了。 如果按照每个VMA计算,求和,可以通过/proc/pid/smaps文件去计算,这个文件比maps的文件更详细,值得仔细分析,计算验证下:

cat /proc/12375/smaps|grep Size|grep -v Page|awk -F: '{print $2}'|awk '{sum += $1}; END {print sum}'
2764

虚拟内存对的上,实际内存计算:

# cat /proc/12375/smaps|grep Rss|grep -v Page|awk -F: '{print $2}'|awk '{sum += $1}; END {print sum}'
1388

这个和实际内存对不上,按照Pss(即共享内存做了平分处理后,仍然有差距),差距原因是应用申请内存通过c的库申请的,库申请的时候也会多申请一些,还有一些对齐之类的,有些差异可能也正常。

还有个比较简单的计算程序内存的方法:

oot@ubuntu-lab:/home/miao/c-test/mm-test# cat /proc/24546/status
Name:   a.out
Umask:  0002
State:  S (sleeping)
Tgid:   24546
Ngid:   0
Pid:    24546
PPid:   5359
TracerPid:      0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
FDSize: 256
Groups: 4 24 27 30 46 110 1000 
NStgid: 24546
NSpid:  24546
NSpgid: 24546
NSsid:  5359
VmPeak:  1051332 kB
VmSize:  1051332 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:   1049776 kB
VmRSS:   1049776 kB
RssAnon:         1048672 kB
RssFile:            1104 kB
RssShmem:              0 kB
....

VmRSS 这个即是程序占用的内存,一般情况下VmRSS = RssAnon+RssFile+RssShmem

四 系统内存分析

其实我们遇到系统的性能问题,如果怀疑是内存问题,那么很有可能用free命令看下,然后top命令看看,top下对程序的占用内存情况进行排序,找到可疑进程,然后再做上面的进程占用内存情况的分析。(整个系统所占内存包括内核占的内存和应用程序所占内存两个部分)。

其实最该看的两个内核导出文件:/proc/meminfo和 /proc/vmstat 前者是内存的占用分类情况,而后者是内存分配,规整、脏页回写等更细节的内存数据的动态变化,通过这些变化发现问题,由于后者不是重点,重点来看下前者,在我机器上统计如下:

miao@ubuntu-lab:~$ cat /proc/meminfo 
MemTotal:        4926744 kB    //所有可用的内存大小,物理内存减去预留位和内核使用。系统从加电开始到引导完成,firmware/BIOS要预留一些内存,内核本身要占用一些内存,最后剩下可供内核支配的内存就是MemTotal。这个值在系统运行期间一般是固定不变的,重启会改变。
MemFree:         3663620 kB  //表示系统尚未使用的内存。
MemAvailable:    4209668 kB //真正的系统可用内存,系统中有些内存虽然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可以回收,所以这部分可回收的内存加上MemFree才是系统可用的内存
Buffers:           78416 kB   //用来给块设备做缓存的内存,(文件系统的 metadata、pages)
Cached:           661976 kB     //分配给文件缓冲区的内存,例如vi一个文件,就会将未保存的内容写到该缓冲区
SwapCached:            0 kB   //被swap到磁盘上的匿名内存,又一次被拉入内存统计
Active:           325864 kB    //经常使用的高速缓冲存储器页面文件大小
Inactive:         618264 kB   //不经常使用的高速缓冲存储器文件大小
Active(anon):       4564 kB   //活跃的匿名内存
Inactive(anon):   215464 kB   //不活跃的匿名内存
Active(file):     321300 kB    //活跃的文件使用内存
Inactive(file):   402800 kB  //不活跃的文件使用内存
Unevictable:       19372 kB    //不能被释放的内存页
Mlocked:           19372 kB   //系统调用 mlock 家族允许程序在物理内存上锁住它的部分或全部地址空间。这将阻止Linux 将这个内存页调度到交换空间(swap space),即使该程序已有一段时间没有访问这段空间
SwapTotal:       4194300 kB //交换空间总内存
SwapFree:        4194300 kB    //交换空间空闲内存
Dirty:               148 kB              //等待被写回到磁盘的脏内存
Writeback:             0 kB            //正在被写回的脏内存
AnonPages:        223144 kB    //未映射页的内存/映射到用户空间的非文件页表大小
MApped:           210380 kB      //映射文件内存
Shmem:             13168 kB      //已经被分配的共享内存,所有tmpfs类型的文件系统占用的空间都计入共享内存
KReclaimable:      60332 kB 
Slab:             137076 kB         //内核数据结构缓存
SReclaimable:      60332 kB   //可收回slab内存
SUnreclaim:        76744 kB    //不可收回slab内存
KernelStack:        7568 kB    // 每一个用户线程都会分配一个kernel stack(内核栈),内核栈虽然属于线程,但用户态的代码不能访问,只有通过系统调用(syscall)、自陷(trap)或异常(exception)进入内核态的时候才会用到,也就是说内核栈是给kernel code使用的。在x86系统上Linux的内核栈大小是固定的8K或16K
PageTables:         5876 kB    //管理内存分页的索引表(物理内存和虚拟内存映射表)的大小 
NFS_Unstable:          0 kB // The amount, in kibibytes, of NFS pages sent to the server but not yet committed to the stable storage.
Bounce:                0 kB // 有些老设备只能访问低端内存,比如16M以下的内存,当应用程序发出一个I/O 请求,DMA的目的地址却是高端内存时(比如在16M以上),内核将在低端内存中分配一个临时buffer作为跳转,把位于高端内存的缓存数据复制到此处。这种额外的数据拷贝被称为“bounce buffering”,会降低I/O 性能。大量分配的bounce buffers 也会占用额外的内存。
WritebackTmp:          0 kB    // USE用于临时写回缓冲区的内存
CommitLimit:     6657672 kB       // 系统实际可分配内存总量
Committed_AS:    1742228 kB   // 当前已分配的内存总量
VmallocTotal:   34359738367 kB // 虚拟内存空间能分配的总内存大小
VmallocUsed:       57524 kB       // 虚拟内存空间使用的内存大小
VmallocChunk:          0 kB          // 虚拟内存空间可分配的最大的逻辑连续的内存大小
Percpu:            89600 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB //AnonHugePages统计的是Transparent HugePages (THP),THP与Hugepages不是一回事,与进程的RSS/PSS是有重叠的,如果用户进程用到了THP,进程的RSS/PSS也会相应增加
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
FileHugePages:         0 kB
FilePmdMapped:         0 kB
HugePages_Total:       0   //超级大页总大小如果进程使用了Hugepages,它的RSS/PSS不会增加。
HugePages_Free:        0  //超级大页空闲大小
HugePages_Rsvd:        0 // 超级大页剩余内存
HugePages_Surp:        0 // 剩余超级大页数量
Hugepagesize:       2048 kB  //超级大页 尺寸为2MB
Hugetlb:               0 kB
DirectMap4k:      198464 kB //DirectMap所统计的不是关于内存的使用,而是一个反映TLB效率的指标 表示映射为4kB的内存数量 TLB(Translation Lookaside Buffer)是位于CPU上的缓存,用于将内存的虚拟地址翻译成物理地址,由于TLB的大小有限,不能缓存的地址就需要访问内存里的page table来进行翻译,速度慢很多。
DirectMap2M:     3913728 kB // 表示映射为2MB的内存数量
DirectMap1G:     1048576 kB // 表示映射为1GB的内存数量

五 申请内存分析

刚才的系统内存分析,可以分析各类内存的大小,还需要根据不同种类的内存大小,对应到应用程序里面,是应用程序中申请哪类内存引起的那,所以这个章节是通过测试程序申请内存看meminfo中各项内存分类的大小变化,从而等到遇到问题的时候就可以通过meminfo中的数据猜测到底是哪里数据影响的。

下图左边是程序通过glibc的库申请内存,注意这里面的程序也可能是c程序,也可能是JAVA程序,很多语言最终底层申请内存还是通过c的库来申请,c的库申请内存的内存主要就有两种形式,一种是mmap映射的方式,对应虚拟内存的映射内存区,另一种方式是通过brk或sbrk来申请小内存(一般是小于128kb的内存),这些虚拟内存并没有真实分配,只有真正使用的时候通过缺页中断,分配真实的物理内存。

linux中申请内存的情况分析

 

图来自极客时间

按照内存类型对程序运行所需的内存进行分类,构成如下的思维导图:

linux中申请内存的情况分析

 

重点需要关注的:

  1. 私有匿名内存,比如我们通过malloc或calloc、或new申请的内存。
  2. 共享匿名内存,tmpfs这里面如果你程序写临时文件写这里面,需要自己负责删除。
  3. 私有文件映射,比如通过mmap映射读文件。
  4. 共享文件映射,如果自己申请需要自己释放。

5.1 malloc申请内存-匿名内存测试

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define SIZE 1024*1024*1024

int main (void)
{
  char * p = (char *) malloc(SIZE);
  memset(p,0x0,SIZE);
  while(1) {
       printf("PID:%dn",getpid());
       sleep(50);
  }
free(p);
return 0;
}

先清理下内存,然后运行此程序,查看/proc/meminfo的变化。

root@ubuntu-lab:/home/miao/c-test/mm-test# diff meminfo.old meminfo.new
2,5c2,5
< MemFree:         4217504 kB
< MemAvailable:    4230356 kB
< Buffers:            2040 kB
< Cached:           218572 kB
---
> MemFree:         3165428 kB
> MemAvailable:    3180980 kB
> Buffers:            4396 kB
> Cached:           218776 kB
7,8c7,8
< Active:            37908 kB
< Inactive:         380112 kB
---
> Active:            40424 kB
> Inactive:        1428872 kB
10,12c10,12
< Inactive(anon):   211228 kB
< Active(file):      35272 kB
< Inactive(file):   168884 kB
---
> Inactive(anon):  1259804 kB
> Active(file):      37788 kB
> Inactive(file):   169068 kB
17c17
< Dirty:               204 kB
---
> Dirty:                12 kB
19,20c19,20
< AnonPages:        217032 kB
< Mapped:           213968 kB
---
> AnonPages:       1265628 kB
> Mapped:           213988 kB
22,27c22,27
< KReclaimable:      33828 kB
< Slab:             109880 kB
< SReclaimable:      33828 kB
< SUnreclaim:        76052 kB
< KernelStack:        7472 kB
< PageTables:         5576 kB
---
> KReclaimable:      33832 kB
> Slab:             109808 kB
> SReclaimable:      33832 kB
> SUnreclaim:        75976 kB
> KernelStack:        7456 kB
> PageTables:         7628 kB
32c32
< Committed_AS:    1732340 kB
---
> Committed_AS:    2781300 kB

重点几个:

1. Inactive(anon) 增加1GB的非活跃匿名内存;
2. Committed_AS 分配的内存增加了1GB;
3. Inactive 非活跃匿名内存增加1GB;
4. AnonPages 匿名内存页增加了1GB;
5. MemAvailable 和MemFree 减少了1GB。

5.2 mmap申请私有匿名内存

#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#define MEMSIZE 1024*1024*1024
#define MPFILE "./mmapfile"

int main()
{
    void *ptr;
    int fd;
    fd = open(MPFILE, O_RDWR);
    if (fd < 0) {
        perror("open()");
        exit(1);
    }
// 匿名方式申请的时候会忽略最后两个参数的
    ptr = mmap(NULL, MEMSIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, fd, 0);
    if (ptr == NULL) {
        perror("mmap()");
        exit(1);
    }
    printf("%pn", ptr);
    bzero(ptr, MEMSIZE);
    printf("pid=%dn", getpid());
    sleep(50);
    munmap(ptr, MEMSIZE);
    close(fd);
    exit(1);
}

结果同上。

5.3 mmap申请匿名共有映射

和上面代码类似,只是一句代码不同:

  ptr = mmap(NULL, MEMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, fd, 0);

主要变化内存:

MemFree: 空闲内存减少1GB。
MemAvailable: 可用内存减少1GB。
Cached:   缓存增加1GB。
Inactive: 增加了1GB。
Inactive(anon): 增加1GB。
Mapped: 增加1GB。
Shmem: 共享内存增加了1GB。
Committed_AS: 申请内存增加了1GB。

5.4 mmap申请私有文件映射内存

和上面的代码类似,只是:

    ptr = mmap(NULL, MEMSIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);

主要变化内存:

1. MemFree 空闲内存少了2GB。
2. MemAvailable 内存少了1GB,因为缓存是可以释放的。
3. Cached 增加了1GB。
4. Inactive 增加了2GB。
5. Inactive(anon) 增加了1GB。
6. Inactive(file) 增加了1GB。
7. AnonPages 增加了1GB
8. Committed_AS 增加了1GB。

私有文件映射,在进程内存种看到的是占用Inactive(file)内存,只所以也会占用Inactive(anon) ,是在于私有文件映射很特殊,它在写的时候,不会同步到后台的文件上去,采用写时复制,写时候会拷贝一份到物理内存中(匿名内存)。

5.5 mmap申请共享文件映射

代码和上面类似不同点:

    ptr = mmap(NULL, MEMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

结果如下:

1. MemFree 少1GB。
2. Cached 增加了1GB。
3. Inactive 增加了1GB。
4. Inactive(file) 增加了1GB。
5. Mapped 增加了1GB。

注意只有共享内存的mmap才会在Mapped内存,共享内存映射算Cache所以这里面增加了,因为第一次读文件,所以是Inactive(file),所以增加了1GB。

注意这种方式有两个有用的点:

  1. 映射的内存是共享的,所以可以多个在多个进程间共享。
  2. 对映射的内存写入或修改后,系统会自动同步到对应的文件中,这个很好用。

总结

  1. 只要是私有的mmap映射,对于系统看来都是匿名页面。
  2. 只要是共享的mmap映射,对系统占用的内存都是MMaped内存。

5.6 shm共享内存

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#define MEMSIZE 1024*1024*1024
int
main()
{
    int shmid;
    char *ptr;
    pid_t pid;
    struct shmid_ds buf;
    int ret;
   // 创建1GB大小权限为0600的共享内存
    shmid = shmget(IPC_PRIVATE, MEMSIZE, 0600);
    if (shmid<0) {
        perror("shmget()");
        exit(1);
    }
   // 获取共享内存信息复制到buf中,包括权限大小等
    ret = shmctl(shmid, IPC_STAT, &buf);
    if (ret < 0) {
        perror("shmctl()");
        exit(1);
    }
    printf("shmid: %dn", shmid);
    printf("shmsize: %dn", buf.shm_segsz);
 
    pid = fork();
    if (pid<0) {
        perror("fork()");
        exit(1);
    }
   // 子进程
    if (pid==0) {
        // 将共享内存映射到本进程的内存空间
        ptr = shmat(shmid, NULL, 0);
        if (ptr==(void*)-1) {
            perror("shmat()");
            exit(1);
        }
        bzero(ptr, MEMSIZE);
         // 拷贝hello到里面去
        strcpy(ptr, "Hello!");
        exit(0);
    } else {
       // 等子进程写入结束
        wait(NULL);
     // 将共享内存映射到本进程的内存空间
        ptr = shmat(shmid, NULL, 0);
        if (ptr==(void*)-1) {
            perror("shmat()");
            exit(1);
        }
      // 输出退出
        puts(ptr);
        exit(0);
    }
}

注意:

  1. 代码没有调用int shmdt(const void * shmadr); 来清理共享内存和进程的关联;
  2. 代码也未调用 shmctl的IPC_RMID删除共享内存 来删除内存,所以程序运行结束,还是会占用共享内存的,如下查看:
root@ubuntu-lab:/home/miao/c-test/mm-test# ipcs -m
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x000631ba 0          postgres   600        56         6                       
0x00000000 3          root       600        1073741824 0      

继续看下内存的变化:

1. MemFree 和MemAvailable 减少了1GB。
2. Cached 占用增加了1GB,可见shm是属于cache的。
3. Inactive 增加了1GB。
4. Inactive(anon) 增加了1GB。
5. Shmem 增加了1GB。
6. Committed_AS增加了1GB。

shm被视为基于tmpfs文件系统的内存页,既然基于文件系统,就不算匿名页,所以不被计入/proc/meminfo中的AnonPages。

清理共享内存:

root@ubuntu-lab:/home/miao/c-test/mm-test# ipcrm -m 3
root@ubuntu-lab:/home/miao/c-test/mm-test# ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x000631ba 0          postgres   600        56         6   

5.7 tmpfs

测试:

mkdir /tmp/tmpfs
mount -t tmpfs -o size=2G none /tmp/tmpfs/

#占用空间
root@ubuntu-lab:/home/miao/c-test/mm-test# dd if=/dev/zero of=/tmp/tmpfs/testfile bs=1G count=1

1+0 records in
1+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 3.15495 s, 340 MB/s
root@ubuntu-lab:/home/miao/c-test/mm-test# 
root@ubuntu-lab:/home/miao/c-test/mm-test# df -h
none                               2.0G  1.0G  1.0G  50% /tmp/tmpfs

内存变化:

1. MemFree 和MemAvailable 减少了1GB。
2. Cached 占用增加了1GB,可见shm是属于cache的。
3. Inactive 增加了1GB。
4. Inactive(anon) 增加了1GB。
5. Shmem 增加了1GB。
6. Committed_AS增加了1GB。

和shm一样的内存变化,注意用:echo 3 > /proc/sys/vm/drop_caches 并不会释放内存,而且通过free -h 可以看到有1GB的空间。

root@ubuntu-lab:/home/miao/c-test/mm-test# free -h
               total        used        free      shared  buff/cache   available
Mem:           4.7Gi       474Mi       3.0Gi       1.0Gi       1.2Gi       3.0Gi

清理:

rm /tmp/tmpfs/testfile 
umount  /tmp/tmpfs/

参考:

[linux内存占用分析之meminfo - SegmentFault 思否](https://segmentfault.com/a/1190000022518282)
[/proc/meminfo之谜 | Linux Performance](http://linuxperf.com/?p=142)
代码来自:深入浅出Linux 内核管理和调试
[https://www.jianshu.com/p/eece39beee20](https://www.jianshu.com/p/eece39beee20)


Tags:内存   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Rust编程语言的内存安全与性能:如何平衡?
Rust编程语言自诞生以来,就以其独特的内存安全特性和高性能而备受瞩目。然而,如何在保证内存安全的同时,实现高效的性能,一直是Rust开发者们面临的挑战。本文将深入探讨Rust的内...【详细内容】
2024-04-12  Search: 内存  点击:(12)  评论:(0)  加入收藏
微软 Edge 浏览器将迎来“内存限制器”功能,用户可自主控制 Edge 内存占用
IT之家 3 月 28 日消息,微软即将为其 Edge 浏览器带来一项实用新功能,据悉该公司正在测试一项内置的内存限制器,这项功能可以让用户限制 Edge 所占用的内存,防止浏览器超出内存...【详细内容】
2024-03-29  Search: 内存  点击:(21)  评论:(0)  加入收藏
.Net开发中十种常见的内存错误以及相应的解决方案
在.Net开发中,为内存管理方面提供了许多便利,但仍然存在一些常见的错误和陷阱。这些错误可能导致内存泄漏、性能下降、异常抛出等问题,严重影响应用程序的稳定性和性能。在软件...【详细内容】
2024-03-26  Search: 内存  点击:(18)  评论:(0)  加入收藏
在Linux系统中,如何处理内存管理和优化的问题?
本文对 Linux 内存管理和优化的一些高级技巧的详细介绍,通过高级的内存管理技巧,可以帮助系统管理员和开发人员更好地优化 Linux 系统的内存使用情况,提高系统性能和稳定性。在...【详细内容】
2024-03-26  Search: 内存  点击:(18)  评论:(0)  加入收藏
Java 8 内存管理原理解析及内存故障排查实践
本文介绍Java8虚拟机的内存区域划分、内存垃圾回收工作原理解析、虚拟机内存分配配置,以及各垃圾收集器优缺点及场景应用、实践内存故障场景排查诊断,方便读者面临内存故障时...【详细内容】
2024-03-20  Search: 内存  点击:(18)  评论:(0)  加入收藏
记一次Rust内存泄漏排查之旅
在某次持续压测过程中,我们发现 GreptimeDB 的 Frontend 节点内存即使在请求量平稳的阶段也在持续上涨,直至被 OOM kill。我们判断 Frontend 应该是有内存泄漏了,于是开启了排...【详细内容】
2024-02-27  Search: 内存  点击:(15)  评论:(0)  加入收藏
固态硬盘和内存条有什么区别?分享以下四点可以了解的
内存条和固态硬盘都是计算机硬件中常见的存储设备,但是它们的作用和工作原理存在一定的区别。所以,在本期的内容当中,小编就为大家分享以下四点可以了解的,一起来看下吧。固态硬...【详细内容】
2024-02-06  Search: 内存  点击:(79)  评论:(0)  加入收藏
电脑虚拟内存怎么设置?1分钟快速增加内存!
“我电脑里的内存好像不太够用,因此,我想在电脑里增加一些虚拟内存。不知道我应该怎么操作呢?有什么比较简单的此操作方法吗?” 虚拟内存是计算机系统内存管理的一种技术,它为程...【详细内容】
2024-02-06  Search: 内存  点击:(66)  评论:(0)  加入收藏
手机的运存和内存:各自的作用与关联
在当今的手机市场中,无论是高端旗舰还是经济型手机,都会提及“运存”和“内存”这两个参数。那么,究竟什么是手机的运存和内存?它们各自的作用又是什么呢?本文将为您详细解析。一...【详细内容】
2024-02-05  Search: 内存  点击:(45)  评论:(0)  加入收藏
在项目中如何避免和解决Java内存泄漏问题
在Java中,内存泄漏通常指的是程序中存在一些不再使用的对象或数据结构仍然保持对内存的引用,从而导致这些对象无法被垃圾回收器回收,最终导致内存占用不断增加,进而影响程序的性...【详细内容】
2024-02-01  Search: 内存  点击:(78)  评论:(0)  加入收藏
▌简易百科推荐
微软 Win11 Linux 子系统(WSL)发布 2.2.2 版本
IT之家 4 月 8 日消息,微软近日更新 Windows Subsystem for Linux(WSL),最新 2.2.2 版本中带来了诸多改进,重点更新了 nft 规则,可以让 IPv6 流量通过 Linux 容器。图源: dev.to,AI...【详细内容】
2024-04-08    IT之家  Tags:Linux   点击:(10)  评论:(0)  加入收藏
从原理到实践:深入探索Linux安全机制
Linux 是一种开源的类Unix操作系统内核,由Linus Torvalds在1991年首次发布,其后又衍生出许多不同的发行版(如Ubuntu、Debian、CentOS等)。前言本文将从用户和权限管理、文件系统...【详细内容】
2024-03-27  凡夫编程  微信公众号  Tags:Linux安全   点击:(26)  评论:(0)  加入收藏
在Linux系统中,如何处理内存管理和优化的问题?
本文对 Linux 内存管理和优化的一些高级技巧的详细介绍,通过高级的内存管理技巧,可以帮助系统管理员和开发人员更好地优化 Linux 系统的内存使用情况,提高系统性能和稳定性。在...【详细内容】
2024-03-26  编程技术汇  微信公众号  Tags:Linux   点击:(18)  评论:(0)  加入收藏
Linux 6.9-rc1 内核发布:AMD P-State 首选核心、BH 工作队列
IT之家 3 月 25 日消息,Linus Torvalds 宣布,Linux 6.9 内核的首个 RC(候选发布)版 Linux 6.9-rc1 发布。▲ Linux 6.9-rc1Linus 表示,Linux 内核 6.9 看起来是一个“相当正常”...【详细内容】
2024-03-25    IT之家  Tags:Linux   点击:(16)  评论:(0)  加入收藏
轻松实现Centos系统的软件包安装管理:yum指令实战详解
yum 是一种用于在 CentOS、Red Hat Enterprise Linux (RHEL) 等基于 RPM 的 Linux 发行版上安装、更新和管理软件包的命令行工具。它可以自动解决软件包依赖关系,自动下载并...【详细内容】
2024-02-27  凡夫贬夫  微信公众号  Tags:Centos   点击:(61)  评论:(0)  加入收藏
Win + Ubuntu 缝合怪:第三方开发者推出“Wubuntu”Linux 发行版
IT之家 2 月 26 日消息,一位第三方开发者推出了一款名为“Wubuntu”的缝合怪 Linux 发行版,系统本身基于 Ubuntu,但界面为微软 Windows 11 风格,甚至存在微软 Windows 徽标。据...【详细内容】
2024-02-27    IT之家  Tags:Ubuntu   点击:(55)  评论:(0)  加入收藏
Linux中磁盘和文件系统工作原理解析
在Linux系统中,一切皆文件的概念意味着所有的资源,包括普通文件、目录以及设备文件等,都以文件的形式存在。这种统一的文件系统管理方式使得Linux系统具有高度的灵活性和可扩展...【详细内容】
2024-02-20  王建立    Tags:Linux   点击:(61)  评论:(0)  加入收藏
Linux子系统概览
inux操作系统是一个模块化的系统,由多个子系统组成。这些子系统协同工作,使Linux能够执行各种任务。了解Linux的子系统有助于更好地理解整个操作系统的运作机制。以下是Linux...【详细内容】
2024-02-01    简易百科  Tags:Linux   点击:(89)  评论:(0)  加入收藏
Linux内核:系统之魂与交互之源
内核,作为任何基于Linux的操作系统的心脏,扮演着至关重要的角色。它不仅是计算机系统软件与硬件之间的桥梁,更是确保系统稳定、高效运行的关键。内核提供了一系列核心功能,为上...【详细内容】
2024-02-01  松鼠宝贝    Tags:Linux内核   点击:(74)  评论:(0)  加入收藏
如何确保Linux进程稳定与持久
在Linux系统中,进程的稳定性与持久性对于维持系统的持续运行至关重要。然而,由于各种原因,进程可能会面临崩溃或系统重启的情况。为了确保关键进程能够持续运行,我们必须采取一...【详细内容】
2024-01-19  松鼠宝贝    Tags:Linux进程   点击:(94)  评论:(0)  加入收藏
站内最新
站内热门
站内头条