精华内容
下载资源
问答
  • linux

    千次阅读 2019-05-29 16:18:09
    页是Linux内核中的概念,因为硬盘的读写速度远远赶不上内存的速度,系统就把读写比较频繁的数据事先放到内存中,以提高读写速度,这就是高速缓存,Linux是以页作为高速缓存的单位,当进程修改了高速缓存里的数据时...

    脏页是Linux内核中的概念,因为硬盘的读写速度远远赶不上内存的速度,系统就把读写比较频繁的数据事先放到内存中,以提高读写速度,这就是高速缓存,Linux是以页作为高速缓存的单位,当进程修改了高速缓存里的数据时,该页就被内核标记为脏页,内核将会在合适的时间把脏页的数据写到磁盘中,以保持高速缓存中的数据同磁盘中的数据是一致的。

    展开全文
  • 如果你运维过一个大数据集群,你就能够明白内存对于集群主节点来说是一种稀缺资源,特别是集群越大,机器内存问题给集群带来的问题就越明显且越频繁。在我管理的这么多大数据集群中,该问题现象就层出不穷。下面对...

    全文共10789字,阅读约需3min。

    如果你运维过一个大数据集群,你就能够明白内存对于集群主节点来说是一种稀缺资源,特别是集群越大,机器内存问题给集群带来的问题就越明显且越频繁。
    在我管理的这么多大数据集群中,该问题现象就层出不穷。下面对其中一次现象进行了总结。

    问题现象

    1) 一台主机无缘无故死机;
    2) 其上namenode服务无响应其发生准备切换。

    问题排查思路是:

    1. 接收到主机网络不通告警;

    2. 接收到其上namenode服务STOP告警;

    3. 查看备节点是否成功切换为主节点;

    4. 查看zkfc日志确定failover原因;

    5. 重启(如果需要)故障主机,备份日志,启动nn服务,查看主机日志确认主机故障原因。

    其实正确的处理问题路径是:重启主机->启动nn->查看日志定位原因。这里不对问题处理思路作深究,仅重点阐述本案中主机死机的原因。

    主机死机,一般是要查看/var/log/message日志,发现提示

    echo 0/proc/sys/kernel/hung_task_timeout_secs

    完整的日志如下:

    Mar 28 03:12:47 namenode01 collectd[1731]: write_graphite plugin: send to epc-graphite-server:2003 (tcp) failed with status 110 (Connection timed out)
    Mar 28 03:12:47 namenode01 collectd[1731]: Filter subsystem: Built-in target `write': Dispatching value to all write plugins failed with status -1.
    Mar 28 03:12:47 namenode01 collectd[1731]: Filter subsystem: Built-in target `write': Some write plugin is back to normal operation. `write' succeeded.
    Mar 28 03:14:31 namenode01 kernel: INFO: task kworker/15:2:22246 blocked for more than 120 seconds.
    Mar 28 03:14:31 namenode01 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
    Mar 28 03:14:31 namenode01 kernel: kworker/15:2    D ffff88208618bdd8     0 22246      2 0x00000080
    Mar 28 03:14:31 namenode01 kernel: ffff88208618bbf0 0000000000000046 ffff8828e3130000 ffff88208618bfd8
    Mar 28 03:14:31 namenode01 kernel: ffff88208618bfd8 ffff88208618bfd8 ffff8828e3130000 ffff88208618bd60
    Mar 28 03:14:31 namenode01 kernel: 7fffffffffffffff ffff88208618bd58 ffff8828e3130000 ffff88208618bdd8
    Mar 28 03:14:31 namenode01 kernel: Call Trace:
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff816a94e9>] schedule+0x29/0x70
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff816a6ff9>] schedule_timeout+0x239/0x2c0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff8105aeae>] ? physflat_send_IPI_mask+0xe/0x10
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff81050b5c>] ? native_smp_send_reschedule+0x4c/0x70
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810c0548>] ? resched_curr+0xa8/0xc0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810c12c8>] ? check_preempt_curr+0x78/0xa0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810c1309>] ? ttwu_do_wakeup+0x19/0xd0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff816a989d>] wait_for_completion+0xfd/0x140
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810c4810>] ? wake_up_state+0x20/0x20
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810b07ea>] kthread_create_on_node+0xaa/0x140
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a93c0>] ? manage_workers.isra.24+0x2a0/0x2a0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a8f8b>] create_worker+0xeb/0x200
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a9216>] manage_workers.isra.24+0xf6/0x2a0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a9743>] worker_thread+0x383/0x3c0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a93c0>] ? manage_workers.isra.24+0x2a0/0x2a0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810b098f>] kthread+0xcf/0xe0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff816b4f58>] ret_from_fork+0x58/0x90
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
    Mar 28 03:16:31 namenode01 kernel: INFO: task kworker/2:2:11678 blocked for more than 120 seconds.
    Mar 28 03:16:31 namenode01 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
    Mar 28 03:16:31 namenode01 kernel: kworker/2:2     D ffff88003922bdd8     0 11678      2 0x00000080
    Mar 28 03:16:31 namenode01 kernel: ffff88003922bbf0 0000000000000046 ffff881fffd86eb0 ffff88003922bfd8
    Mar 28 03:16:31 namenode01 kernel: ffff88003922bfd8 ffff88003922bfd8 ffff881fffd86eb0 ffff88003922bd60
    Mar 28 03:16:31 namenode01 kernel: 7fffffffffffffff ffff88003922bd58 ffff881fffd86eb0 ffff88003922bdd8
    Mar 28 03:16:31 namenode01 kernel: Call Trace:
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff816a94e9>] schedule+0x29/0x70
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff816a6ff9>] schedule_timeout+0x239/0x2c0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810c8f18>] ? __enqueue_entity+0x78/0x80
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810cf90c>] ? enqueue_entity+0x26c/0xb60
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff816a989d>] wait_for_completion+0xfd/0x140
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810c4810>] ? wake_up_state+0x20/0x20
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810b07ea>] kthread_create_on_node+0xaa/0x140
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a93c0>] ? manage_workers.isra.24+0x2a0/0x2a0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a8f8b>] create_worker+0xeb/0x200
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a9216>] manage_workers.isra.24+0xf6/0x2a0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a9743>] worker_thread+0x383/0x3c0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a93c0>] ? manage_workers.isra.24+0x2a0/0x2a0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810b098f>] kthread+0xcf/0xe0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff816b4f58>] ret_from_fork+0x58/0x90
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
    Mar 28 03:16:31 namenode01 kernel: INFO: task kworker/15:2:22246 blocked for more than 120 seconds.
    Mar 28 03:16:31 namenode01 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
    Mar 28 03:16:31 namenode01 kernel: kworker/15:2    D ffff88208618bdd8     0 22246      2 0x00000080
    Mar 28 03:16:31 namenode01 kernel: ffff88208618bbf0 0000000000000046 ffff8828e3130000 ffff88208618bfd8
    Mar 28 03:16:31 namenode01 kernel: ffff88208618bfd8 ffff88208618bfd8 ffff8828e3130000 ffff88208618bd60
    Mar 28 03:16:31 namenode01 kernel: 7fffffffffffffff ffff88208618bd58 ffff8828e3130000 ffff88208618bdd8

    原因在于,默认情况下, Linux会最多使用40%的可用内存作为文件系统缓存。当超过这个阈值后,文件系统会把将缓存中的内存全部写入磁盘, 导致后续的IO请求都是同步的。将缓存写入磁盘时,有一个默认120秒的超时时间。

    出现上面的问题的原因是IO子系统的处理速度不够快,不能在120秒将缓存中的数据全部写入磁盘。IO系统响应缓慢,导致越来越多的请求堆积,最终系统内存全部被占用,导致系统失去响应。

    这个Linux延迟写机制带来的问题,并且在主机内存越大时,出现该问题的可能性更大。研究发现This is a know bug

    This is a know bug. By default Linux uses up to 40% of the available memory for file system caching. After this mark has been reached the file system flushes all outstanding data to disk causing all following IOs going synchronous. For flushing out this data to disk this there is a time limit of 120 seconds by default. In the case here the IO subsystem is not fast enough to flush the data withing 120 seconds. This especially happens on systems with a lof of memory.

    The problem is solved in later kernels and there is not “fix” from Oracle. I fixed this by lowering the mark for flushing the cache from 40% to 10% by setting “vm.dirty_ratio=10” in /etc/sysctl.conf. This setting does not influence overall database performance since you hopefully use Direct IO and bypass the file system cache completely.

    链接:nfo-task-blocked-for-more-than-120-seconds

    关于脏数据,有几个配置:

    vm.dirty_background_ratio是内存可以填充“脏数据”的百分比。这些“脏数据”在稍后是会写入磁盘的,pdflush/flush/kdmflush这些后台进程会稍后清理脏数据。举一个例子,我有32G内存,那么有3.2G的内存可以待着内存里,超过3.2G的话就会有后来进程来清理它。

    vm.dirty_ratio 是绝对的脏数据限制,内存里的脏数据百分比不能超过这个值,如果超过,将强制刷写到磁盘。如果脏数据超过这个数量,新的IO请求将会被阻挡,直到脏数据被写进磁盘。这是造成IO卡顿的重要原因,但这也是保证内存中不会存在过量脏数据的保护机制。

    vm.dirty_expire_centisecs 指定脏数据能存活的时间。在这里它的值是30秒。当 pdflush/flush/kdmflush 进行起来时,它会检查是否有数据超过这个时限,如果有则会把它异步地写到磁盘中。毕竟数据在内存里待太久也会有丢失风险。

    vm.dirty_writeback_centisecs 指定多长时间
    pdflush/flush/kdmflush 这些进程会起来一次。

    调优

    我们可以从以下思路进行调优:

    1. 减少脏数据的比例,避免刷写超时

    2. 减小脏数据在内存中的存放时间,避免积少成多

    修改相应参数

    临时修改

    # sysctl -w vm.dirty_ratio=10
    # sysctl -w vm.dirty_background_ratio=5
    # sysctl -p

    永久修改

    #vi /etc/sysctl.conf
    写入
    vm.dirty_background_ratio = 5
    vm.dirty_ratio = 10
    sysctl -p

    关于脏数据,这里简单说一下:

    脏数据 由于Linux内核实现的一种主要磁盘缓存的存在,也就是页高速缓存(cache)。页高速缓存的缓存作用,写操作实际上会被延迟。当页高速缓存中的数据比后台存储的数据更新时,那么该数据就被称做脏数据。

    参考

    • 关于Linux内核延迟写机制,可以学习以下文章:http://ilinuxkernel.com/?p=1578

    • 关于页高速缓存和脏数据等其他IO术语不清楚的同学,参考几个IO术语:https://blog.51cto.com/qixue/1906775

    --------


    39f10a6df39b60be1d068f5c0f9cdcf3.png

    展开全文
  • 记一次Linux主机内存脏数据引发的NameNode故障,主机提示echo 0 > /proc/sys/kernel/hung_task_timeout_secs。内存脏数据是什么,如何调优。

    全文共10789字,阅读约需3min。

    如果你运维过一个大数据集群,你就能够明白内存对于集群主节点来说是一种稀缺资源,特别是集群越大,机器内存问题给集群带来的问题就越明显且越频繁。
    在我管理的这么多大数据集群中,该问题现象就层出不穷。下面对其中一次现象进行了总结。

    问题现象

    1. 一台主机无缘无故死机;
    2. 其上namenode服务无响应其发生准备切换。

    问题排查思路是:

    1. 接收到主机网络不通告警;
    2. 接收到其上namenode服务STOP告警;
    3. 查看备节点是否成功切换为主节点;
    4. 查看zkfc日志确定failover原因;
    5. 重启(如果需要)故障主机,备份日志,启动nn服务,查看主机日志确认主机故障原因。

    其实正确的处理问题路径是:重启主机->启动nn->查看日志定位原因。这里不对问题处理思路作深究,仅重点阐述本案中主机死机的原因。

    主机死机,一般是要查看/var/log/message日志,发现提示:echo 0 > /proc/sys/kernel/hung_task_timeout_secs.

    完整的日志如下:

    Mar 28 03:12:47 namenode01 collectd[1731]: write_graphite plugin: send to epc-graphite-server:2003 (tcp) failed with status 110 (Connection timed out)
    Mar 28 03:12:47 namenode01 collectd[1731]: Filter subsystem: Built-in target `write': Dispatching value to all write plugins failed with status -1.
    Mar 28 03:12:47 namenode01 collectd[1731]: Filter subsystem: Built-in target `write': Some write plugin is back to normal operation. `write' succeeded.
    Mar 28 03:14:31 namenode01 kernel: INFO: task kworker/15:2:22246 blocked for more than 120 seconds.
    Mar 28 03:14:31 namenode01 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
    Mar 28 03:14:31 namenode01 kernel: kworker/15:2    D ffff88208618bdd8     0 22246      2 0x00000080
    Mar 28 03:14:31 namenode01 kernel: ffff88208618bbf0 0000000000000046 ffff8828e3130000 ffff88208618bfd8
    Mar 28 03:14:31 namenode01 kernel: ffff88208618bfd8 ffff88208618bfd8 ffff8828e3130000 ffff88208618bd60
    Mar 28 03:14:31 namenode01 kernel: 7fffffffffffffff ffff88208618bd58 ffff8828e3130000 ffff88208618bdd8
    Mar 28 03:14:31 namenode01 kernel: Call Trace:
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff816a94e9>] schedule+0x29/0x70
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff816a6ff9>] schedule_timeout+0x239/0x2c0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff8105aeae>] ? physflat_send_IPI_mask+0xe/0x10
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff81050b5c>] ? native_smp_send_reschedule+0x4c/0x70
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810c0548>] ? resched_curr+0xa8/0xc0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810c12c8>] ? check_preempt_curr+0x78/0xa0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810c1309>] ? ttwu_do_wakeup+0x19/0xd0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff816a989d>] wait_for_completion+0xfd/0x140
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810c4810>] ? wake_up_state+0x20/0x20
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810b07ea>] kthread_create_on_node+0xaa/0x140
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a93c0>] ? manage_workers.isra.24+0x2a0/0x2a0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a8f8b>] create_worker+0xeb/0x200
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a9216>] manage_workers.isra.24+0xf6/0x2a0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a9743>] worker_thread+0x383/0x3c0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810a93c0>] ? manage_workers.isra.24+0x2a0/0x2a0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810b098f>] kthread+0xcf/0xe0
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff816b4f58>] ret_from_fork+0x58/0x90
    Mar 28 03:14:31 namenode01 kernel: [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
    Mar 28 03:16:31 namenode01 kernel: INFO: task kworker/2:2:11678 blocked for more than 120 seconds.
    Mar 28 03:16:31 namenode01 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
    Mar 28 03:16:31 namenode01 kernel: kworker/2:2     D ffff88003922bdd8     0 11678      2 0x00000080
    Mar 28 03:16:31 namenode01 kernel: ffff88003922bbf0 0000000000000046 ffff881fffd86eb0 ffff88003922bfd8
    Mar 28 03:16:31 namenode01 kernel: ffff88003922bfd8 ffff88003922bfd8 ffff881fffd86eb0 ffff88003922bd60
    Mar 28 03:16:31 namenode01 kernel: 7fffffffffffffff ffff88003922bd58 ffff881fffd86eb0 ffff88003922bdd8
    Mar 28 03:16:31 namenode01 kernel: Call Trace:
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff816a94e9>] schedule+0x29/0x70
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff816a6ff9>] schedule_timeout+0x239/0x2c0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810c8f18>] ? __enqueue_entity+0x78/0x80
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810cf90c>] ? enqueue_entity+0x26c/0xb60
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff816a989d>] wait_for_completion+0xfd/0x140
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810c4810>] ? wake_up_state+0x20/0x20
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810b07ea>] kthread_create_on_node+0xaa/0x140
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a93c0>] ? manage_workers.isra.24+0x2a0/0x2a0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a8f8b>] create_worker+0xeb/0x200
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a9216>] manage_workers.isra.24+0xf6/0x2a0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a9743>] worker_thread+0x383/0x3c0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810a93c0>] ? manage_workers.isra.24+0x2a0/0x2a0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810b098f>] kthread+0xcf/0xe0
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff816b4f58>] ret_from_fork+0x58/0x90
    Mar 28 03:16:31 namenode01 kernel: [<ffffffff810b08c0>] ? insert_kthread_work+0x40/0x40
    Mar 28 03:16:31 namenode01 kernel: INFO: task kworker/15:2:22246 blocked for more than 120 seconds.
    Mar 28 03:16:31 namenode01 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
    Mar 28 03:16:31 namenode01 kernel: kworker/15:2    D ffff88208618bdd8     0 22246      2 0x00000080
    Mar 28 03:16:31 namenode01 kernel: ffff88208618bbf0 0000000000000046 ffff8828e3130000 ffff88208618bfd8
    Mar 28 03:16:31 namenode01 kernel: ffff88208618bfd8 ffff88208618bfd8 ffff8828e3130000 ffff88208618bd60
    Mar 28 03:16:31 namenode01 kernel: 7fffffffffffffff ffff88208618bd58 ffff8828e3130000 ffff88208618bdd8
    

    原因在于,默认情况下, Linux会最多使用40%的可用内存作为文件系统缓存。当超过这个阈值后,文件系统会把将缓存中的内存全部写入磁盘, 导致后续的IO请求都是同步的。将缓存写入磁盘时,有一个默认120秒的超时时间。

    出现上面的问题的原因是IO子系统的处理速度不够快,不能在120秒将缓存中的数据全部写入磁盘。IO系统响应缓慢,导致越来越多的请求堆积,最终系统内存全部被占用,导致系统失去响应。

    这个Linux延迟写机制带来的问题,并且在主机内存越大时,出现该问题的可能性更大。研发发现This is a know bug

    This is a know bug. By default Linux uses up to 40% of the available memory for file system caching. After this mark has been reached the file system flushes all outstanding data to disk causing all following IOs going synchronous. For flushing out this data to disk this there is a time limit of 120 seconds by default. In the case here the IO subsystem is not fast enough to flush the data withing 120 seconds. This especially happens on systems with a lof of memory.

    The problem is solved in later kernels and there is not “fix” from Oracle. I fixed this by lowering the mark for flushing the cache from 40% to 10% by setting “vm.dirty_ratio=10” in /etc/sysctl.conf. This setting does not influence overall database performance since you hopefully use Direct IO and bypass the file system cache completely.

    链接:nfo-task-blocked-for-more-than-120-seconds

    关于脏数据,有几个配置:

    vm.dirty_background_ratio是内存可以填充“脏数据”的百分比。这些“脏数据”在稍后是会写入磁盘的,pdflush/flush/kdmflush这些后台进程会稍后清理脏数据。举一个例子,我有32G内存,那么有3.2G的内存可以待着内存里,超过3.2G的话就会有后来进程来清理它。

    vm.dirty_ratio 是绝对的脏数据限制,内存里的脏数据百分比不能超过这个值,如果超过,将强制刷写到磁盘。如果脏数据超过这个数量,新的IO请求将会被阻挡,直到脏数据被写进磁盘。这是造成IO卡顿的重要原因,但这也是保证内存中不会存在过量脏数据的保护机制。

    vm.dirty_expire_centisecs 指定脏数据能存活的时间。在这里它的值是30秒。当 pdflush/flush/kdmflush 进行起来时,它会检查是否有数据超过这个时限,如果有则会把它异步地写到磁盘中。毕竟数据在内存里待太久也会有丢失风险。

    vm.dirty_writeback_centisecs 指定多长时间
    pdflush/flush/kdmflush 这些进程会起来一次。

    调优

    我们可以从以下思路进行调优:

    1. 减少脏数据的比例,避免刷写超时
    2. 减小脏数据在内存中的存放时间,避免积少成多

    修改相应参数

    临时修改

    # sysctl -w vm.dirty_ratio=10
    # sysctl -w vm.dirty_background_ratio=5
    # sysctl -p
    

    永久修改

    #vi /etc/sysctl.conf
    写入
    vm.dirty_background_ratio = 5
    vm.dirty_ratio = 10
    
    sysctl -p
    

    关于脏数据,这里简单说一下:

    脏数据 由于Linux内核实现的一种主要磁盘缓存的存在,也就是页高速缓存(cache)。页高速缓存的缓存作用,写操作实际上会被延迟。当页高速缓存中的数据比后台存储的数据更新时,那么该数据就被称做脏数据。

    参考


    在这里插入图片描述


    展开全文
  • Linux mmap内存映射

    2021-03-25 21:19:37
    将最近网上搜索的资料统一整理下,方便后续复查。 一、什么是mmap ...实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写页面到对应的文件磁盘上,即完成了

    将最近网上搜索的资料统一整理下,方便后续复查。

    一、什么是mmap

    mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系,函数原型如下 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

    实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。如下图所示

     

    mmap除了可以减少read,write等系统调用以外,还可以减少内存的拷贝次数,比如在read调用时,一个完整的流程是操作系统读磁盘文件到页缓存,再从页缓存将数据拷贝到read传递的buffer里,而如果使用mmap之后,操作系统只需要将磁盘读到页缓存,然后用户就可以直接通过指针的方式操作mmap映射的内存,减少了从内核态到用户态的数据拷贝。

     

    mmap适合于对同一块区域频繁读写的情况,比如一个64M的文件存储了一些索引信息,我们需要频繁修改并持久化到磁盘,这样可以将文件通过mmap映射到用户虚拟内存,然后通过指针的方式修改内存区域,由操作系统自动将修改的部分刷回磁盘,也可以自己调用msync手动刷磁盘。

    内核角度分析mmap原理,这篇博客图文并茂,直接参考就好了。 linux内存映射mmap原理分析 - 鱼思故渊的专栏 - CSDN博客 blog.csdn.net/yusiguyuan/…

    映射只不过是映射到虚拟内存,不用担心映射的文件太大。

    1. 每个进程的4G内存空间只是虚拟内存空间,每次访问内存空间的某个地址,都需要把地址翻译为实际物理内存地址
    2. 所有进程共享同一物理内存,每个进程只把自己目前需要的虚拟内存空间映射并存储到物理内存上。

     

     

    详细虚拟内存的内容还是参考大神总结

     

    linux 进程的虚拟内存 - fengxin的博客 - CSDN博客 blog.csdn.net/fengxinlinu…

    二、mmap参数说明

    映射文件或设备到内存中,取消映射就是munmap函数。

    语法如下:

    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length);

    该函数主要用途有三个:

    • 将普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,用内存读写取代I/O读写,以获得较高的性能;
    • 将特殊文件进行匿名内存映射,为关联进程提供共享内存空间;
    • 为无关联的进程间的Posix共享内存(SystemV的共享内存操作是shmget/shmat)

    我们来看下函数的入参选择:

    ➢ 参数addr:

    指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。

    ➢ 参数length:

    代表将文件中多大的部分映射到内存。

    ➢ 参数prot:

    映射区域的保护方式。可以为以下几种方式的组合:

    PROT_EXEC 映射区域可被执行

    PROT_READ 映射区域可被读取

    PROT_WRITE 映射区域可被写入

    PROT_NONE 映射区域不能存取

    ➢ 参数flags:

    影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。

    MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此。

    MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。

    MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。

    MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。

    MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。

    MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。

    ➢ 参数fd:

    要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。

    ➢ 参数offset:

    文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。

    返回说明

    成功执行时,mmap()返回被映射区的指针,munmap()返回0。失败时,mmap()返回MAP_FAILED[其值为(void *)-1],munmap返回-1。errno被设为以下的某个值。

    EACCES:访问出错

    EAGAIN:文件已被锁定,或者太多的内存已被锁定

    EBADF:fd不是有效的文件描述词

    EINVAL:一个或者多个参数无效

    ENFILE:已达到系统对打开文件的限制

    ENODEV:指定文件所在的文件系统不支持内存映射

    ENOMEM:内存不足,或者进程已超出最大内存映射数量

    EPERM:权能不足,操作不允许

    ETXTBSY:已写的方式打开文件,同时指定MAP_DENYWRITE标志

    SIGSEGV:试着向只读区写入

    SIGBUS:试着访问不属于进程的内存区

    三、mmap与直接IO(read、write)的效率比较

    不能简单的说哪个效率高,要看具体实现与具体应用。 write read mmap实际流程如下:

     

     

     

     

    无论是通过mmap方式或read/write方式访问文件在内核中都必须经过两个缓存:一个是用address_space来组织的以页为基础的缓存;一个是以buffer来组织的缓存,但实际上这两个缓存只是同一个缓冲池里内容的不同组织方式。当需要从文件读写内容时,都经过 address_space_operation中提供的函数也就是说路径是一致的。如果是用read/write方式,用户须向内核指定要读多少,内核再把得到的内容从内核缓冲池拷向用户空间;写也须要有一个大致如此的过程。

     

    mmap的优势在于通过把文件的某一块内容映射到用户空间上,用户可以直接向内核缓冲池读写这一块内容,这样一来就少了内核与用户空间的来回拷贝所以通常更快。但 mmap方式只适用于更新、读写一块固定大小的文件区域而不能做像诸如不断的写内容进入文件导到文件增长这类的事。

    二者的主要区别在于,与mmap和memcpy相比,read和write执行了更多的系统调用,并做了更多的复制。read和write将数据从内核缓冲区中复制到应用缓冲区,然后再把数据从应用缓冲区复制到内核缓冲区。而mmap和memcpy则直接把数据从映射到地址空间的一个内核缓冲区复制到另一个内核缓冲区。当引用尚不存在的内存页时,这样的复制过程就会作为处理页错误的结果而出现(每次错页读发生一次错误,每次错页写发生一次错误)。

    所以他们两者的效率的比较就是系统调用和额外的复制操作的开销和页错误的开销之间的比较,哪一个开销少就是哪一个表现更好。用mmap可以避免与读写打交道,这样可以简化程序逻辑,有利于编程实现。

    系统调用mmap()可以将某文件映射至内存(进程空间),如此可以把对文件的操作转为对内存的操作,以此避免更多的lseek()与read()、write()操作,这点对于大文件或者频繁访问的文件而言尤其受益。但有一点必须清楚:mmap的addr与offset必须对齐一个内存页面大小的边界,即内存映射往往是页面大小的整数倍,否则maaped_file_size%page_size内存空间将被闲置浪费。映射时,指定offset最好是内存页面大小的整数倍。

    内存文件映射的使用:

    (1)大数据量文件的读取,有效的提高磁盘和内存间数据通信的性能;

    (2)进程间快速的共享内存,实现进程间高效的通信。

    内存映射文件性能高于普通IO的原因:

    内存文件映射和普通的文件IO都是要通过文件系统和硬盘驱动拷贝数据到内存中,内存文件映射数据越大越快主要是:

    (1)实际拷贝数据前,需要建立映射信息,内存文件映射已经提前准备好了映射关系,内核调度好了进程内的内存块,交付给内核进行了预先处理,内存文件映射会消耗掉一些时间。

    (2)实际拷贝时候,内存文件映射将磁盘数据直接拷贝到用户进程内存空间只进行了一次拷贝,而普通的IO是先将文件拷贝到内核缓存空间,然后才拷贝到用户进程内存空间,进行了两次拷贝。

    下面是一个使用普通的fread函数和内存映射文件函数,读取不同大小的磁盘文件的性能分析表:

     

    综合: 当读写磁盘文件的数据较小(少于1MB)时候,使用内存文件映射和普通IO是差异很小的,所以建议使用普通IO就可以了;当很多文件的大小在几十MB, 几百MB, 或者1GB以上的文件数据需要进行较频繁的访问,或者一开始需要全部加载这些大文件的时候,那么就需要考虑使用内存文件映射了。

     

    四、网上测试实例

    (1)demo1 演示一下,将文件/tmp/file_mmap中的字符转成大写,分别使用mmap与read/write二种方法实现。 先创建/tmp/file_mmap文件,该文件写入www.baidu.com,使用strace统计系统调用。

    /*
    * @file: t_mmap.c
    */
    #include <stdio.h>
    #include <ctype.h>
    #include <sys/mman.h> /*mmap munmap*/
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
     
    int main(int argc, char *argv[])
    {
     int fd;
     char *buf;
     off_t len;
     struct stat sb;
     char *fname = "/tmp/file_mmap";
     
     fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
     if (fd == -1)
     {
      perror("open");
      return 1;
     }
     if (fstat(fd, &sb) == -1)
     {
      perror("fstat");
      return 1;
     }
     
     buf = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
     if (buf == MAP_FAILED)
     {
      perror("mmap");
      return 1;
     }
     
     if (close(fd) == -1)
     {
      perror("close");
      return 1;
     }
     
     for (len = 0; len < sb.st_size; ++len)
     {
      buf[len] = toupper(buf[len]);
      /*putchar(buf[len]);*/
     }
     
     if (munmap(buf, sb.st_size) == -1)
     {
      perror("munmap");
      return 1;
     }
     return 0;
    }
    复制代码

    自己测试运行结果:

    root@chenwr-pc:/home/workspace/test# gcc tmp.c -o run 
    root@chenwr-pc:/home/workspace/test# strace ./run 
    execve("./run", ["./run"], [/* 22 vars */]) = 0
    brk(0)                                  = 0x1ffa000
    access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=106932, ...}) = 0
    mmap(NULL, 106932, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcab05de000
    close(3)                                = 0
    access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P \2\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=1857312, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcab05dd000
    mmap(NULL, 3965632, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcab000e000
    mprotect(0x7fcab01cc000, 2097152, PROT_NONE) = 0
    mmap(0x7fcab03cc000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1be000) = 0x7fcab03cc000
    mmap(0x7fcab03d2000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fcab03d2000
    close(3)                                = 0
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcab05db000
    arch_prctl(ARCH_SET_FS, 0x7fcab05db740) = 0
    mprotect(0x7fcab03cc000, 16384, PROT_READ) = 0
    mprotect(0x600000, 4096, PROT_READ)     = 0
    mprotect(0x7fcab05f9000, 4096, PROT_READ) = 0
    munmap(0x7fcab05de000, 106932)          = 0
    open("/tmp/file_mmap", O_RDWR|O_CREAT, 0600) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=14, ...}) = 0
    mmap(NULL, 14, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0x7fcab05f8000
    close(3)                                = 0
    munmap(0x7fcab05f8000, 14)              = 0
    exit_group(0)                           = ?
    +++ exited with 0 +++
    复制代码

    该文件已经变成大写。

    root@chenwr-pc:/tmp# cat file_mmap 
    WWW.BAIDU.COM
    复制代码

    网上该demo的说明:

    open("/tmp/file_mmap", O_RDWR|O_CREAT, 0600) = 3 //open,返回fd=3
    fstat64(3, {st_mode=S_IFREG|0644, st_size=18, ...}) = 0 //fstat, 即文件大小18
    mmap2(NULL, 18, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xb7867000 //mmap文件fd=3
    close(3)  = 0 //close文件fd=3
    munmap(0xb7867000, 18)= 0  //munmap,移除0xb7867000这里的内存映射
    这里mmap的addr是0(NULL),offset是18,并不是一个内存页的整数倍,即有4078bytes(4kb-18)内存空间被闲置浪费了。
    复制代码

    (2)demo2 read的方式

    #include <stdio.h>
    #include <ctype.h>
    #include <sys/mman.h> /*mmap munmap*/
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
     int fd, len;
     char *buf;
     char *fname = "/tmp/file_mmap";
     ssize_t ret;
     struct stat sb;
     
     fd = open(fname, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
     if (fd == -1)
     {
      perror("open");
      return 1;
     }
     if (fstat(fd, &sb) == -1)
     {
      perror("stat");
      return 1;
     }
     
     buf = malloc(sb.st_size);
     if (buf == NULL)
     {
      perror("malloc");
      return 1;
     }
     ret = read(fd, buf, sb.st_size);
     for (len = 0; len < sb.st_size; ++len)
     {
      buf[len] = toupper(buf[len]);
      /*putchar(buf[len]);*/
     }
     
     lseek(fd, 0, SEEK_SET);
     ret = write(fd, buf, sb.st_size);
     if (ret == -1)
     {
      perror("error");
      return 1;
     }
     
     if (close(fd) == -1)
     {
      perror("close");
      return 1;
    }
    free(buf);
     return 0;
    }
    复制代码

    自己测试运行的结果:

    root@chenwr-pc:/home/workspace/test# strace ./run 
    execve("./run", ["./run"], [/* 22 vars */]) = 0
    brk(0)                                  = 0x13ac000
    access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=106932, ...}) = 0
    mmap(NULL, 106932, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb98f1d7000
    close(3)                                = 0
    access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
    open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P \2\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=1857312, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb98f1d6000
    mmap(NULL, 3965632, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb98ec07000
    mprotect(0x7fb98edc5000, 2097152, PROT_NONE) = 0
    mmap(0x7fb98efc5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1be000) = 0x7fb98efc5000
    mmap(0x7fb98efcb000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb98efcb000
    close(3)                                = 0
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb98f1d4000
    arch_prctl(ARCH_SET_FS, 0x7fb98f1d4740) = 0
    mprotect(0x7fb98efc5000, 16384, PROT_READ) = 0
    mprotect(0x600000, 4096, PROT_READ)     = 0
    mprotect(0x7fb98f1f2000, 4096, PROT_READ) = 0
    munmap(0x7fb98f1d7000, 106932)          = 0
    open("/tmp/file_mmap", O_RDWR|O_CREAT, 0600) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=14, ...}) = 0
    brk(0)                                  = 0x13ac000
    brk(0x13cd000)                          = 0x13cd000
    read(3, "www.baidu.com\n", 14)          = 14
    lseek(3, 0, SEEK_SET)                   = 0
    write(3, "WWW.BAIDU.COM\n", 14)         = 14
    close(3)                                = 0
    exit_group(0)                           = ?
    +++ exited with 0 +++
    复制代码

    网上该demo的说明:

    open("/tmp/file_mmap", O_RDWR|O_CREAT, 0600) = 3 //open, fd=3
    fstat64(3, {st_mode=S_IFREG|0644, st_size=18, ...}) = 0 //fstat, 其中文件大小18
    brk(0) = 0x9845000  //brk, 返回当前中断点
    brk(0x9866000)  = 0x9866000  //malloc分配内存,堆当前最后地址
    read(3, "www.perfgeeks.com\n", 18)= 18 //read
    lseek(3, 0, SEEK_SET) = 0 //lseek
    write(3, "WWW.PERFGEEKS.COM\n", 18)  = 18 //write
    close(3)  = 0 
    复制代码

    这里通过read()读取文件内容,toupper()后,调用write()写回文件。因为文件太小,体现不出read()/write()的缺点:频繁访问大文件,需要多个lseek()来确定位置。每次编辑read()/write(),在物理内存中的双份数据。 当然,不可以忽略创建与维护mmap()数据结构的成本。需要注意:并没有具体测试mmap vs read/write,即不能一语断言谁孰谁劣,具体应用场景具体评测分析。 你只是要记住:mmap内存映射文件之后,操作内存即是操作文件,可以省去不少系统内核调用(lseek, read, write)。

    五、自己写的demo

    #include <stdio.h>
    #include <ctype.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/time.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    #include <time.h>
    #define INT64U          unsigned long long 
    
    #define MSG_ERR     1
    #define MSG_WARN    2
    #define MSG_INFO    3
    #define MSG_DBG     4
    #define MSG_NOR     5
    
    #define MSG_HEAD     ("libfat->")
    #define PRTMSG(level, fmt, args...)\
    do {\
        if (level <= MSG_NOR) {\
            if (level <= MSG_NOR) {\
                printf("%s, %s, line %d: " fmt,__FILE__,__FUNCTION__,__LINE__, ##args);\
            } else {\
                printf("%s:" fmt, MSG_HEAD, ##args);\
            }\
        }\
    } while(0)
    
    typedef unsigned char       BOOLEAN;
    typedef unsigned char       INT8U;
    typedef unsigned int        INT16U;
    typedef unsigned long       INT32U;
    
    typedef signed char         INT8S;
    typedef signed int          INT16S;
    typedef signed long         INT32S;
    
    char *filename = "./lt00001";
    //char *filename = "/mnt/sdisk/video/lt00004";
    char *data = "1111111111\
    2222222222\
    3333333333\
    4444444444";
    INT32S data_len = 40;//单次写入的数据长度
    struct timeval t_start, t_end;
    struct stat file_info;
    long cost_time = 0;
    int write_num = 1000;
    
    INT32S mmap_write(INT32S fd, INT64U offset, void *data, INT32S data_len)
    {
        char *buf = NULL;
    
     	if (fstat(fd, &file_info) == -1) {
    		perror("fstat");
    		PRTMSG(MSG_ERR, "[cwr] Get file info failed\n");
    		return -1;
    	}
    	buf = mmap(0, file_info.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
     	if (buf == MAP_FAILED) {
    		perror("mmap");
    		PRTMSG(MSG_ERR, "[cwr] mmap failed\n");
    		return -1;
    	} 
    	//offset = (INT64U)((order)*sizeof(FAT_FILE_LIST_T));
    	memcpy(buf+offset, data, data_len);
    	if (munmap(buf, file_info.st_size) == -1) {
    		perror("munmap");
    		PRTMSG(MSG_ERR, "[cwr] munmap failed\n");
    		return -1;
    	}
    	return data_len;
    }
    int write_test()
    {
    	int fd, ret, i, data_size;
    	INT64U ret64, offset;
    	int ret_len = 0;
    	time_t starttime, endtime;
    
    	fd = open(filename, O_RDWR);
    	if (fd < 0) {
    		printf("[cwr] open file faild\n");
    	}
    	gettimeofday(&t_start, NULL);
    	for (i=0; i<write_num; i++) {
    		offset = i*data_len;
    		ret64 = lseek64(fd, offset, SEEK_SET);
            if (ret64 == -1LL) {
                printf("lseek data fail\n");
                return -1;
            }
    		ret_len = write(fd, data, data_len);
    		if (ret_len != data_len) {
    			printf("[cwr] count = %d; write error\n", i);
    			close(fd);
    			return -1;
    		}
    	}
    	gettimeofday(&t_end, NULL);
    	printf("[cwr] test end, count = %d\n", i);
    	close(fd);
    	return 0;
    }
    int mmap_write_test()
    {
    	 int fd, ret, i, data_size;
    	 INT64U ret64, offset;
    	 int ret_len = 0;
    
        fd = open(filename, O_RDWR);
        if (fd < 0) {
            printf("[cwr] open file faild\n");
        }
    	gettimeofday(&t_start, NULL);
        for (i=0; i<write_num; i++) {
            offset = i*data_len;
            ret_len = mmap_write(fd, offset, data, data_len);
            if (ret_len != data_len) {
                printf("[cwr] count = %d; mmap write error\n", i);
                close(fd);
                return -1;
            }
        }
    	gettimeofday(&t_end, NULL);
        printf("[cwr] mmap write test end, count = %d\n", i);
    
    	close(fd);
        return 0;
    
    }
    void main()
    {
    	int ret;
    
    	memset(&file_info, 0, sizeof(file_info));
    #if 1
    	ret = write_test();
    
    	if (ret != 0) {
    		printf("[cwr] write_test failed\n");
    	}
    #endif
    #if 0
        ret = mmap_write_test();
    
        if (ret != 0) {
            printf("[cwr] mmap_write_test failed\n");
        }
    #endif
    	cost_time = t_end.tv_usec - t_start.tv_usec;
    	printf("Start time: %ld us\n", t_start.tv_usec);
    	printf("End time: %ld us\n", t_end.tv_usec);
    	printf("Cost time: %ld us\n", cost_time);
    
    	while(1) {
    		sleep(1);
    	}
    }
    复制代码

    运行结果:

    write的方式获取的时间

     

    使用mmap的方式去操作

     

    后续不映射整个文件的空间大小,而是映射要写入数据的长度40字节

     

    buf = mmap(0, 40, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset*4*1024)
    复制代码

    为何测试mmap效率并没有更高效。

     

     

     
    展开全文
  • 疯狂内核之——Linux虚拟内存

    热门讨论 2011-05-30 23:38:37
    4.4 刷新内存映射的页 203 4.5 非线性内存映射 210 第五章 页面的回收 215 5.1 页框回收概念 215 5.1.1 选择目标页 216 5.1.2 PFRA设计 217 5.2 反向映射技术 218 5.2.1 匿名页的反向映射 220 5.2.2 优先搜索树 ...
  • BDI机制原本主要是用于检测磁盘的繁忙程度等作用,从2.6.19内核开始,将此部分功能整合到了mm/backing_dev.c中,一直到2.6.31内核为止,其功能也只是在不段的完善,但是数据的下刷依然是依靠pdflush。自2.6.32内核...
  • linux内核的子系统在处理写入时复制至产生了竞争条件,恶意用户可利用此漏洞来获取高权限,对只读内存映射进行访问。 竞争条件,指的是任务执行顺序异常,可导致应用奔溃,或令攻击者有机可乘,进一步执行其他代码...
  • Linux内存管理

    2017-06-12 22:02:59
    free -m ...# sync ---将数据刷新到磁盘 # echo 3 > /proc/sys/vm/drop_caches ---清除OS cache # swapoff -a && swapon -a http://www.2cto.com/os/201703/615315.html To free pagecache:仅清除页
  • mmap内存映射原理 ...实现这样的映射后,进程就可以采用指针的方式读写操作这一块内存,而系统会自动回写页面(未提交的数据)到对应文件磁盘上,即完成了对文件的操作而不是调用read/write等系统调用,...
  • linux内存管理学习心得(二)

    千次阅读 2013-03-19 15:43:36
    前面linux内存管理学习心得(一)也已经说了关于页的概念,在内核下面是把物理页(页框)作为分配的基本单元,内核下使用struct page结构体来表示系统中的物理页其中该结构体表示页是否被锁定在内存中,是否为页...
  • Linux kernel 2.x至4.8.3之前的4.x版本中的mm/gup.c文件存在竞争条件问题漏洞,该漏洞源于程序没有正确处理copy-on-write(COW)功能写入只读内存映射。本地攻击者可利用该漏洞获取权限。 影响版本 从 2007 年发布...
  • 【随笔】Linux

    2021-01-08 17:46:46
    相较之内存,磁盘是一个低速设备,因此Linux中会通过一种叫“磁盘高速缓存”的软件机制来允许将磁盘上的一些数据保留在内存中,以加快访问速度。页高速缓存page cache就是Linux内核所使用的主要磁盘高速缓存。几乎...
  • 实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也...
  • 页(物理页): 内核把物理页作为内存管理的最小单位,用struct ...flag用来存放页的状态,包括这个页是不是的,是不是被锁定在内存中,它至少可以同时表示32种不同的状态。 count存放页的引用计数,通常用page...
  • Linux内存分析 | mmap

    2018-06-13 00:47:19
    1 mmap基本概念 mmap是一种内存映射文件的方法,即将一个文件或者其它对象...实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写页面到对应的文件磁盘上,即完成了对文件的...
  • 1. page cache Linux读写文件过程; read:用户进程调用read命令,内核查询读取的文件内容...cache),不在,同read,从硬盘读取该页4~8K到内存,再往5k处写入10byte,标明该页为页; 写回磁盘时机,则由内存管理的BIO
  • 本文将从 从硬件原理 到内核实现 配置内存的参数(内存什么时候回收,数据什么时候收回?) 从应用程序上的内存泄漏还有工程中一些常遇见的问题 ,比如 DMA 的内存从哪里来?连续内存分配器?来理解内存管理。 ...
  • 暂时目前的环境处理方法比较简单: ...每十分钟执行一次,先将数据写回硬盘,之后释放缓存页和入口信息和节点信息等; -------------------参考链接:https://www.linuxidc.com/Linux/2010-0...
  • 目录 一、swap分区 1. swap分区的创建 2. swap的数据结构 二、swap out 1. 回收流程 ...由于内存和磁盘的读写性能差异较大,Linux...相对的在内存紧张时Linux会将这些缓存回收,将页回写到磁盘中。而在进程的地址.
  • Linux页高速缓存中页的概念

    千次阅读 2018-04-12 21:22:35
    页是Linux内核中的概念,因为硬盘的读写速度远赶不上内存的速度,系统就把读写比较频繁的数据事先放到内存中,以提高读写速度,这就叫高速缓存,linux是以页作为高速缓存的单位,当进程修改了高速缓存里的数据时,...
  • struct page用于管理一个物理页,表示这个页是不是“”、被引用的次数、映射的虚拟地址等信息。 区(zone) 内核采用区对页进行分组。主要是解决以下两个问题:1.一些硬件只能采用特定的内存执行DMA操作。2....
  • linux内核把物理页作为内存管理的基本单位。每一页的大小根据系统架构不同有所区别,32位系统下为4KB,64位系统下为8KB。内存管理单元(MMU)以页为单位来管理系统中的页表,负责虚拟地址到物理地址的转换,用户所...
  • 基于linux kernel的内存调优,附proc详解

    千次阅读 2010-12-28 11:47:00
    基于linux kernel的内存调优,附proc详解. - [linux] Tag:linux kernel proc 版权声明:转载... 1.pdflush,用于回写内存中的数据到硬盘。可以通过 /proc/sys/vm/vm.dirty_background_ratio调整。 首先查看这个值默认
  • 2.1 内存分页 32位:4k/页; 64位:8k/页; linux/mm.h: Struct page { Page_flags_t flags; 页状态:是否,是否被锁定等32种;() Atomic_t _count; 页引用计数;计数为0,则可被申请; Atomic_t _mapcount;
  • 该漏洞是 Linux 内核的内存子系统在处理写时拷贝(Copy-on-Write)时存在条件竞争漏洞, 导致可以破坏私有只读内存映射。黑客可以在获取低权限的的本地用户后,利用此漏洞获取 其他只读内存映射的写权限,进一步获取...
  • 该PTE将包含诸如帧号(我们要引用的主存储器的地址)之类的信息,以及一些其他有用的位(例如,有效/无效位,位,保护位等)。该页表条目(PTE)会告诉您实际页在主内存中的位置。 现在的问题是页面表的放置位置...
  • 其中kmem_cache_cpu的目的是为了从技术层面上提高CPU命中缓存,以及在同一个页面上不出现一个内存(即不同时被多个CPU持有)。我把这个实现机制手工在WINDOWS下实现了一套,在开启多个kmem_cache_cp...
  • 说起页回写,大部分文章介绍的是与页回写有关的参数,...2 dirty_expire_centisecs:控制页在内存中停留的时间,默认30s。就是说,当一个page被标记为页后,30s后就要被回写到磁盘。 3 dirty_background_byt.

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 177
精华内容 70
关键字:

linux脏内存

linux 订阅