http://kenby.iteye.com/blog/1164700

共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式, 因为进程可以直接读写内存,而不需要任何

数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则

只拷贝两次数据: 一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内

存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直

到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映

射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。

一. 传统文件访问

UNIX访问文件的传统方法是用open打开它们, 如果有多个进程访问同一个文件, 则每一个进程在自己的地址空间都包含有该

文件的副本,这不必要地浪费了存储空间. 下图说明了两个进程同时读一个文件的同一页的情形. 系统要将该页从磁盘读到高

速缓冲区中, 每个进程再执行一个存储器内的复制操作将数据从高速缓冲区读到自己的地址空间.

二. 共享存储映射

现在考虑另一种处理方法: 进程A和进程B都将该页映射到自己的地址空间, 当进程A第一次访问该页中的数据时, 它生成一

个缺页中断. 内核此时读入这一页到内存并更新页表使之指向它.以后, 当进程B访问同一页面而出现缺页中断时, 该页已经在

内存, 内核只需要将进程B的页表登记项指向次页即可. 如下图所示:

三、mmap()及其相关系统调用

mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访

问普通内存一样对文件进行访问,不必再调用read(),write()等操作。

mmap()系统调用形式如下:

void* mmap ( void * addr , size_t len , int prot , int flags , int fd , off_t offset )

mmap的作用是映射文件描述符fd指定文件的 [off,off + len]区域至调用进程的[addr, addr + len]的内存区域, 如下图所示:

参数fd为即将映射到进程空间的文件描述字,一般由open()返回,同时,fd可以指定为-1,此时须指定flags参数中的

MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的

进程间通信)。

len是映射到调用进程地址空间的字节数,它从被映射文件开头offset个字节开始算起。

prot 参数指定共享内存的访问权限。可取如下几个值的或:PROT_READ(可读) , PROT_WRITE (可写), PROT_EXEC (可执行), PROT_NONE(不可访问)。

flags由以下几个常值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,其中,MAP_SHARED , MAP_PRIVATE必

选其一,而MAP_FIXED则不推荐使用。

offset参数一般设为0,表示从文件头开始映射。

参数addr指定文件应被映射到进程空间的起始地址,一般被指定一个空指针,此时选择起始地址的任务留给内核来完成。函

数的返回值为最后文件映射到进程空间的地址,进程可直接操作起始地址为该值的有效地址。

四. mmap的例子

shmdata.h

#ifndef _SHMDATA_H_HEADER
#define _SHMDATA_HE_HEADER
#define TEXT_SZ 2048
typedef struct shared_use_st
{int written; // 非 0可读, 0表示 可写char text[TEXT_SZ]; // 记录 写入和 读取 的 文本
}shared_use_st;
#endif

JNI_Shm.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<jni.h>
#include <sys/types.h> /* for open */
#include <sys/stat.h> /* for open */
#include <fcntl.h>     /* for open */
#include<signal.h>
#include <sys/mman.h>
#include "shmdata.h"
#include "JNIHelp.h"
#include<android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-activity", __VA_ARGS__))
#ifndef NELEM
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#endifstatic char CLASS_NAME[] = "com/sailor/ShareMem";
static shared_use_st *use_st = NULL;
static jint throwException(JNIEnv* env, jobject clazz, const char *clsname, const char *msg)
{jclass cls;cls = ( *env)->FindClass(env, clsname);if(cls == NULL){return -1;}    (*env)->ThrowNew(env,cls, msg);return -1;
}static jint openMem(JNIEnv* env, jobject clazz, jstring name, jint length)
{shared_use_st *st = NULL;const char* namestr = (name ? (*env)->GetStringUTFChars(env,name, NULL) : NULL);int result = -1;if(access(namestr, F_OK) == 0){result = open(namestr, O_RDWR);}else{result = open(namestr, O_RDWR|O_CREAT);if(result >= 0){st = (shared_use_st *)malloc(sizeof(shared_use_st));if(st == NULL){LOGE("open malloc failed");}if(write(result, st, sizeof(shared_use_st)) < 0){LOGE("open write failed");}free(st);}}(*env)->ReleaseStringUTFChars(env, name, namestr);return result;}
static jint getMem(JNIEnv* env, jobject clazz,int fd)
{struct stat sb;int result = -1;if(fd >= 0){if((fstat(fd, &sb)) == -1){LOGE("readMem size failed");return result;}if((use_st = (shared_use_st *)mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,fd, 0)) == (void *)-1){LOGE("readMem mmap failed");return result;}result = (jint)use_st->text;LOGE("memory address:%0x", result);}return result;
}static jint writeMem(JNIEnv* env, jobject clazz, int fd, jbyteArray buffer, int size, jint address)
{int ret = 0;if(use_st != NULL && address == (int)use_st->text){(*env)->GetByteArrayRegion(env, buffer, 0, size, (jbyte *)address);ret = size;}return ret;
}
static jbyteArray readMem(JNIEnv* env, jobject clazz, int fd, int address)
{if(fd >= 0){if(use_st != NULL){jbyteArray array = (*env)->NewByteArray(env, TEXT_SZ);(*env)->SetByteArrayRegion(env, array, 0, TEXT_SZ, (char *)address);return array;}}return NULL;
}static void setModeMem(JNIEnv* env, jobject clazz, int mode)
{if(use_st != NULL){use_st->written = mode;}
}static int getModeMem(JNIEnv* env, jobject clazz)
{int nRet = -1;if(use_st != NULL){nRet = use_st->written;}return nRet;
}static  void closeMem(JNIEnv* env, jobject clazz, int fd)
{close(fd);if(use_st != NULL){if ((munmap((void *)use_st, sizeof(shared_use_st))) == -1) {  LOGE("munmap failed");}  }}static  jboolean flushMem(JNIEnv* env, jobject clazz)
{jboolean isFailed = 1;if(use_st != NULL) {if ((msync((void *)use_st, sizeof(shared_use_st), MS_SYNC)) == -1)       {  LOGE("msync failed"); }  else{isFailed = 0;}}return !isFailed;
}static JNINativeMethod mehods[] = {{ "open", "(Ljava/lang/String;I)I", (void *) openMem },{ "read", "(II)[B", (void *) readMem },{ "write", "(I[BII)I", (void *) writeMem },{ "get", "(I)I", (void *) getMem },{ "setMode", "(I)V", (void *) setModeMem },{ "getMode", "()I", (void *) getModeMem },{ "flush", "()Z", (void *) flushMem },{ "close", "(I)V", (void *) closeMem }};static int registerNativeMethods(JNIEnv *env, const char* className,const JNINativeMethod* methods, int numMethods)
{int rc;jclass clazz;clazz = (*env)->FindClass(env, className);if (clazz == NULL) {LOGE("Native registration unable to find class '%s'\n", className);return -1;}if (rc = ((*env)->RegisterNatives(env, clazz, methods, numMethods)) < 0) {LOGE("RegisterNatives failed for '%s' %d\n", className, rc);return -1;}return 0;
}static int register_jni(JNIEnv *env)
{return registerNativeMethods(env, CLASS_NAME, mehods, NELEM(mehods));
}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{JNIEnv* env = NULL;jint result = -1;    //获取JNI版本if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) {LOGE("GetEnv failed!");return result;}InitHelp(env, NULL);if (register_jni(env) < 0) {LOGE("register method failed!");return result;}return JNI_VERSION_1_4;
}

com.sailor.ShareMem.java:

package com.sailor;public class ShareMem {static {// 加载动态库System.loadLibrary("JNIShm");}public native int open(String path, int length);public native void close(int fd);public native int get(int fd);public native byte[] read(int fd, int address);public native int write(int fd, byte[] buffer, int size, int address);public native boolean flush();public native void setMode(int mode);public native int getMode();
}

android1 app:

public void startMem3(View view){mem = new ShareMem();int fd = mem.open(Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.txt",0);Log.d("jacklam", "startMem fd:" + fd);int address = mem.get(fd);Log.d("jacklam", "startMem address:" + address);boolean isFlush = mem.flush();Log.d("jacklam", "flush buffer:" + isFlush);mem.close(fd);}public void startMem2(View view){mem = new ShareMem();int fd = mem.open(Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.txt",0);Log.d("jacklam", "startMem fd:" + fd);int address = mem.get(fd);Log.d("jacklam", "startMem address:" + address);byte[] buffer = mem.read(fd, address);Log.d("jacklam", "read buffer:" + new String(buffer));/*mem.close(fd);*/}public void startMem1(View view){mem = new ShareMem();int fd = mem.open(Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.txt",0);Log.d("jacklam", "startMem fd:" + fd);int address = mem.get(fd);Log.d("jacklam", "startMem address:" + address);byte[] buffer = {'I','I','t'};mem.write(fd, buffer, buffer.length, address);/*mem.close(fd);*/}

android app2:

public void startMem3(View view){mem = new ShareMem();int fd = mem.open(Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.txt",0);Log.d("jacklam", "startMem fd:" + fd);int address = mem.get(fd);Log.d("jacklam", "startMem address:" + address);boolean isFlush = mem.flush();Log.d("jacklam", "flush buffer:" + isFlush);mem.close(fd);}public void startMem2(View view){mem = new ShareMem();int fd = mem.open(Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.txt",0);Log.d("jacklam", "startMem fd:" + fd);int address = mem.get(fd);Log.d("jacklam", "startMem address:" + address);byte[] buffer = mem.read(fd, address);Log.d("jacklam", "read buffer:" + new String(buffer));mem.close(fd);}public void startMem1(View view){mem = new ShareMem();int fd = mem.open(Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.txt",0);Log.d("jacklam", "startMem fd:" + fd);int address = mem.get(fd);Log.d("jacklam", "startMem address:" + address);byte[] buffer = {'I','o','t'};mem.write(fd, buffer, buffer.length, address);mem.close(fd);}

android mmap的使用相关推荐

  1. Android mmap 文件映射到内存介绍

    本文链接: Android mmap 文件映射到内存介绍 Android开发中,我们可能需要记录一些文件.例如记录log文件.如果使用流来写文件,频繁操作文件io可能会引起性能问题. 为了降低写文件的 ...

  2. kotlin中的Map集合类

    Kotlin中的Map分为: 只读Map. 可变的MutableMap(MutableMap.HashMap.LinkedHashMap). Map源码: private object EmptyMa ...

  3. 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 三 | 等待远程函数执行完毕 | 寄存器获取返回值 )

    文章目录 前言 一.等待远程进程 mmap 函数执行完毕 二.从寄存器中获取进程返回值 三.博客资源 前言 前置博客 : [Android 逆向]Android 进程注入工具开发 ( 注入代码分析 | ...

  4. 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 二 | 准备参数 | 远程调用 mmap 函数 )

    文章目录 一.准备 mmap 函数的参数 二.mmap 函数远程调用 一.准备 mmap 函数的参数 上一篇博客 [Android 逆向]Android 进程注入工具开发 ( 注入代码分析 | 远程调 ...

  5. 【Android 逆向】Android 进程代码注入原理 ( 进程注入原理 | 远程调用流程 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )

    文章目录 一.进程注入原理 二.远程调用流程 ( 获取 so 动态库地址 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 ) 一.进程注入原理 调试进程 At ...

  6. 神器Android键值数据库MMKV——基于 mmap 的高性能通用 key-value 组件

    MMKV 是基于 mmap 内存映射的 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强.从 2015 年中至今在微信上使用,其性能和稳定性经过了时间的验证 ...

  7. Android 进程间通信机制(二) mmap 原理

    一. 前言 Binder中一次拷贝的实现就是利用mmap(memory mapping)内存映射机制,我们来看看它的工作原理. 二. 参考文章 下面这几篇文章建议先好好阅读一下,都是总结的很好的文章, ...

  8. mmap内存 android,Android中mmap原理及应用简析

    mmap是Linux中常用的系统调用API,用途广泛,Android中也有不少地方用到,比如匿名共享内存,Binder机制等.本文简单记录下Android中mmap调用流程及原理.mmap函数原型如下 ...

  9. 【Android 逆向】Android 进程注入工具开发 ( 注入代码分析 | 远程调用 目标进程中 libc.so 动态库中的 mmap 函数 一 | mmap 函数简介 )

    文章目录 一.mmap 简介 二.mmap 函数作用 一.mmap 简介 mmap 函数的作用是 将 文件 映射到 内存中 , 映射的单位必须是 PAGE_SIZE ; mmap 函数引入头文件 : ...

最新文章

  1. 从MegaEase看云原生
  2. 一文让你搞懂YOLO难关!
  3. js如何生成一个对象,并转化为json字符串
  4. 2014全年目标及执行情况跟踪
  5. sql OFFSET 和 ORDINAL
  6. 很少有人能把CDN说的这么有趣了
  7. html读取本地txt_利用MySQL/MariaDB的逻辑缺陷伪造恶意服务端读取客户端文件
  8. P4782-[模板]2-SAT问题【tarjan】
  9. Java 数据库连接池的技术选型都应考虑哪些要素
  10. Rabbitmq消息可靠投递和重复消费等问题解决方案
  11. python thread 共享数据
  12. java 对日期的加减运算
  13. Matlab简单教程:函数
  14. 冰封王座人工只能_《冰封王座》地图:重装机兵MMR【V1.42回归版】
  15. “二清”是电商行业在支付清算领域中普遍存在的现实状况?
  16. dns劫持教您dns被劫持如何修复、dns劫持如何修复
  17. 自学软件测试3个月,原来15K也就这么回事...
  18. aabResGuard使用
  19. 目前很穷,有什么办法能快速挣钱?
  20. 存储过程中 IN,OUT,INOUT类型参数的区别

热门文章

  1. 主路径覆盖与基路径覆盖
  2. 如何成为一个好的项目技术管理人员
  3. C#队列Queue实现一个简单的电商网站秒杀程序
  4. 【精品】电商项目 中 基于SPU与SKU的 商品 数据库表设计
  5. 将Win11右键菜单变回Win10风格
  6. what is ITL( Interested Transaction list)
  7. layui loading动画_loading加载和layer.js
  8. 微信小程序歌曲列表页实现
  9. [leetcode]47.全排列2
  10. 关于永磁同步电机机械特性的疑问?