Linux mmap内存映射,Android-App的设计架构经验谈

(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, offset41024)

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

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

《960全网最全Android开发笔记》

《379页Android开发面试宝典》

《507页Android开发相关源码解析》

厂面经、学习笔记、源码讲义、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-cs0uuuc3-1710668516644)]

《960全网最全Android开发笔记》

[外链图片转存中…(img-JSwKiDO1-1710668516644)]

《379页Android开发面试宝典》

[外链图片转存中…(img-L7hhrvST-1710668516644)]

《507页Android开发相关源码解析》

[外链图片转存中…(img-B3Vxp8Sd-1710668516645)]

因为文件太多,全部展示会影响篇幅,暂时就先列举这些部分截图,大家可以**点击这里**自行领取。

  • 22
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值