天天看点

Linux内存--虚拟内存,buffer/cacheLinux内存相关

Linux内存相关

Linux内存--虚拟内存,buffer/cacheLinux内存相关

上图是32位的操作系统的地址空间情况。

申请虚拟内存

首先获取寻址大小:查看cat /proc/cpuinfo

[email protected]:~$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 79
model name      : Intel(R) Xeon(R) CPU E5-2620 v4 @ 2.10GHz
stepping        : 1
microcode       : 0xb00002c
cpu MHz         : 2100.000
cache size      : 20480 KB
physical id     : 0
siblings        : 16
core id         : 0
cpu cores       : 8
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 20
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch epb invpcid_single intel_pt ibrs ibpb stibp kaiser tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm cqm rdseed adx smap xsaveopt cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm arat pln pts
bugs            : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass
bogomips        : 4190.67
clflush size    : 64
cache_alignment : 64
address sizes   : 46 bits physical, 48 bits virtual
power management:
           

由上图可知:

address sizes : 46 bits physical, 48 bits virtual

48位虚拟地址空间,所以可寻址范围2^48, 内核空间和用户空间各占一半;所以用户空间可连续malloc的大小为(2^48)/2 = 2^47 = 2^10 * 2^10 * 2^10 * 2^17

那么我们通过一个例子来进行验证(使用malloc进行虚拟地址的申请,看我们最多能申请多少大小的空间):

测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{

    unsigned long long mem_size = (unsigned long long)(1024*1024*1024)*1;//1G
    printf("mem_size: %llu\n",mem_size);

    int i = 0;
    while(1) {
        i++;
        int* p_malloc;
        p_malloc = (int*)malloc(mem_size);
        printf("p_malloc: %p\n",p_malloc);
        printf("i: %d\n", i);

    }
    return 0;
}

           

[email protected]:~/sunrise/C++/memory_demo$ gcc main_virtual_address.c -o virtual_address

[email protected]:~/sunrise/C++/memory_demo$ ./virtual_address

i: 131070

p_malloc: 0x7fff681fb010

*p_malloc: 0

i: 131071

p_malloc: 0x7fffa821c010

*p_malloc: 0

i: 131072

p_malloc: (nil)

Segmentation fault (core dumped)

可以看到当malloc申请到131072G的时候,malloc出错(超过了可申请的范围);2^17 = 131072

得到总结:

1、malloc是申请连续的虚拟地址空间。

2、虚拟地址可申请的空间,由虚拟地址可寻址范围确认(48 bits virtual)。

3、malloc只是申请虚拟地址空间,并没有真正的使用到物理内存,需要memset才会真正和物理内存建立真正的映射。

buffer/cache

Linux内存--虚拟内存,buffer/cacheLinux内存相关
Linux内存--虚拟内存,buffer/cacheLinux内存相关

进程读写磁盘文件,会使该区域增加;

app <-> buffer/cache <-> disk

应用读取文件:

先读取cache区域,若存在,则返回,若不存在,则直接读取disk内容(同时将内容缓存到cache区域)

应用写文件:

将内容写入buffer,后台线程定时去将buffer回写到disk。

缓存机制优点:减少系统调用次数,降低CPU上下文切换和磁盘访问频率。

缓存(cached)是把读取过的数据保存起来,重新读取时若命中(找到需要的数据)就不要去读硬盘了,若没有命中就读硬盘。其中的数据会根据读取频率进行组织,把最频繁读取的内容放在最容易找到的位置,把不再读的内容不断往后排,直至从中删除。

缓冲(buffers)是根据磁盘的读写设计的,把分散的写操作集中进行,减少磁盘碎片和硬盘的反复寻道,从而提高系统性能。linux有一个守护进程定期清空缓冲内容(即写入磁盘),也可以通过sync命令手动清空缓冲。举个例子吧:我这里有一个ext2的U盘,我往里面cp一个3M的MP3,但U盘的灯没有跳动,过了一会儿(或者手动输入sync)U盘的灯就跳动起来了。卸载设备时会清空缓冲,所以有些时候卸载一个设备时要等上几秒钟。

读取文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    char buf_r[1024];
    int size;
    int fd = open("/home/yms/test/mdc_syslog0.log",O_RDWR);// 该文件为960M,运行完该程序,buffer/cache大小会增加960M
    if (fd == -1) {
        printf("error open file");
    }else {
        while ((size = read( fd, buf_r, 1024))>0) { // 读取普通文件,首次运行,从磁盘中获取,并将其写入到cache中,再次读取时,则从cache中读取
            printf("read form file:%s OK\n",buf_r);
        }
    }
    close(fd);

    while(1) {
    }

    return 0;
}
           

编译及运行

gcc buffer_cache_demo.c -o buffer_cache_demo

./buffer_cache_demo

运行的同时,查看内存占用(top 或者 free)

top信息(运行前):

top - 06:35:46 up 52 days, 3:39, 48 users, load average: 0.00, 0.07, 0.07

Tasks: 582 total, 1 running, 456 sleeping, 121 stopped, 4 zombie

%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

MiB Mem : 128541.3+total, 127718.5+free, 539.234 used, 283.520 buff/cache

MiB Swap: 1950.992 total, 1132.133 free, 818.859 used. 127381.5+avail Mem

运行后

top - 06:44:10 up 52 days, 3:48, 48 users, load average: 1.04, 0.64, 0.31

Tasks: 582 total, 2 running, 455 sleeping, 121 stopped, 4 zombie

%Cpu(s): 3.1 us, 0.0 sy, 0.0 ni, 96.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

MiB Mem : 128541.3+total, 126775.3+free, 539.242 used, 1226.777 buff/cache

MiB Swap: 1950.992 total, 1132.219 free, 818.773 used. 127291.9+avail Mem

再次运行:

top - 06:49:07 up 52 days, 3:53, 48 users, load average: 0.44, 0.47, 0.33

Tasks: 584 total, 2 running, 457 sleeping, 121 stopped, 4 zombie

%Cpu(s): 3.1 us, 0.0 sy, 0.0 ni, 96.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

MiB Mem : 128541.3+total, 126775.7+free, 538.625 used, 1226.984 buff/cache

MiB Swap: 1950.992 total, 1132.285 free, 818.707 used. 127292.4+avail Mem

手动清除缓存:

释放缓存区内存的方法

1)清理pagecache(页面缓存)

[[email protected] ~]# echo 1 > /proc/sys/vm/drop_caches 或者 # sysctl -w vm.drop_caches=1

2)清理dentries(目录缓存)和inodes

[[email protected] ~]# echo 2 > /proc/sys/vm/drop_caches 或者 # sysctl -w vm.drop_caches=2

3)清理pagecache、dentries和inodes

[[email protected] ~]# echo 3 > /proc/sys/vm/drop_caches 或者 # sysctl -w vm.drop_caches=3

上面三种方式都是临时释放缓存的方法,要想永久释放缓存,需要在/etc/sysctl.conf文件中配置:vm.drop_caches=1/2/3,然后sysctl -p生效即可!

手动执行完上面三个清除动作后的top信息

top - 06:50:43 up 52 days, 3:54, 48 users, load average: 0.69, 0.58, 0.39

Tasks: 584 total, 1 running, 458 sleeping, 121 stopped, 4 zombie

%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st

MiB Mem : 128541.3+total, 127723.4+free, 541.965 used, 275.934 buff/cache

MiB Swap: 1950.992 total, 1132.305 free, 818.688 used. 127382.3+avail Mem

继续阅读