MemoryFile匿名共享内存简单案例

匿名共享内存(Ashmem):Ashmem是一种共享内存的机制,它利用了Linux的mmap系统调用,将不同进程中的同一段物理内存映射到进程各自的虚拟地址空间,从而实现高效的进程间共享。它以驱动程序的形式实现在内核空间。它有两个特点,一是能够辅助内存管理系统来有效地管理不再使用的内存块,二是它通过Binder进程间通信机制来实现进程间的内存共享。Ashmem的两个特点就是共享和高效。共享是指可以在不同进程间共享信息,高效则是因为不同进程都是直接进行的内存操作,相对于其他的进程间通信方式来讲,这种方式会更快一些。
 

 Android系统的匿名共享内存系统的主体是以驱动程序的形式实现在内核空间的,同时,在系统运行时库和应用程序框架层提供了访问接口,其中,在系统运行时库提供了C/C++调用接口,而在应用程序框架层提供了Java调用接口。Android开发中通常只需要调用Java接口,而实际上,应用程序框架层的Java调用接口是通过JNI方法来调用系统运行时库的C/C++调用接口,最后进入到内核空间的Ashmem驱动程序去的。

在Android中,主要提供了MemoryFile这个类来供应用使用匿名共享内存。在Android应用程序框架层,提供了一个MemoryFile接口来封装了匿名共享内存文件的创建和使用,通过JNI调用底层C++方法。

下面是通过Binder进程间通信机制来实现进程间的内存共享的例子。

服务端

public class MainActivity extends Activity {
 
	
	private MemoryFile mMemoryFile;
	private final int MEMORY_SIZE = 3133440 + 1;
	private byte[] buffer;
	Binder mBinder;
	private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
        	mBinder = (Binder) service;
        }
        
        public void onServiceDisconnected(ComponentName className) {
        	mBinder = null;
        }
    };
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_main);
        Intent it = new Intent(this, MainService.class);
        startService(it);
        bindService(it, mConnection, Context.BIND_AUTO_CREATE);
        
        try {
        	// 参数1文件名,可为null,参数2文件长度
			mMemoryFile = new MemoryFile("test", MEMORY_SIZE);
		} catch (IOException e) {
			e.printStackTrace();
		}
       
    }
    android.os.Parcel data = android.os.Parcel.obtain();
	android.os.Parcel reply = android.os.Parcel.obtain();
    public void write(View v){
    	EditText et = (EditText) findViewById(R.id.et);
    	buffer = et.getText().toString().getBytes();
    	try {
    		// 写一次 , 读取数据后 数据会被清空
    		// 持续写,不读,数据不会清空,注意数据覆盖(offset值)
			mMemoryFile.writeBytes(buffer, 0, 0, buffer.length);
			 Method getFileDescriptorMethod = mMemoryFile.getClass().getDeclaredMethod("getFileDescriptor");
             if(getFileDescriptorMethod != null){
                 FileDescriptor fileDescriptor = (FileDescriptor) getFileDescriptorMethod.invoke(mMemoryFile);
                 // 序列化,才可传送
                 ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(fileDescriptor);
                 if(mBinder!=null){
                	//data.writeParcelable(pfd, 0);
                	// 或者
                	data.writeFileDescriptor(fileDescriptor);
                	 mBinder.transact(0, data, reply, 0);
                 }
             }
		} catch (Exception e) {
			e.printStackTrace();
			Toast.makeText(this, "写失败", 0).show();
		}
    }
    
    @Override
    protected void onDestroy() {
    	if(mMemoryFile != null){
            mMemoryFile.close();
            mMemoryFile = null;
        }
    	unbindService(mConnection);
    	mConnection = null;
    	super.onDestroy();
    }
}

public class MainService extends Service {
 
	ParcelFileDescriptor pfd;
	
	@Override
	public IBinder onBind(Intent arg0) {
		return new MyBinder();
	}
	
	
	class MyBinder extends Binder {
		@Override
		protected boolean onTransact(int code, Parcel data, Parcel reply,int flags) throws RemoteException {
			switch (code) {
			case 0:
				//pfd = data.readParcelable(null);
				// 或者
				pfd = data.readFileDescriptor();
				break;
			case 1:
				//reply.writeParcelable(pfd,0);
				// 或者
				reply.writeFileDescriptor(pfd.getFileDescriptor());
				break;
 
			default:
				break;
			}
			// 
			return true;
		}
	}
 
}

客户端

public class MainActivity extends Activity {
 
	private final int MEMORY_SIZE = 3133440 + 1;
	private byte[] buffer = new byte[20];
 
	IBinder mBinder;
	private ServiceConnection mConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder service) {
			// 非服务创建进程,获取的Binder只是一个代理Binder对象,不能直接转换
			// mBinder = (Binder) service;
			mBinder = service;
		}
 
		public void onServiceDisconnected(ComponentName className) {
			mBinder = null;
		}
	};
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fragment_main);
 
		Intent it = new Intent("com.xzc.memoryfilewrite.MainService");
		startService(it);
		bindService(it, mConnection, Context.BIND_AUTO_CREATE);
 
	}
 
	public void read(View v) {
		TextView tv = (TextView) findViewById(R.id.tv);
		FileInputStream fi=null;
		FileDescriptor fileDescriptor=null;
		try {
			if (mBinder != null) {
				android.os.Parcel data = android.os.Parcel.obtain();
				android.os.Parcel reply = android.os.Parcel.obtain();
				mBinder.transact(1, data, reply, 0);
				//ParcelFileDescriptor pfd = reply.readParcelable(null);
				// 或者
				ParcelFileDescriptor pfd = reply.readFileDescriptor();
				if(pfd==null){
					buffer = "ParcelFileDescriptor 空指针".getBytes();
					tv.setText(new String(buffer));
					return;
				}
				fileDescriptor = pfd.getFileDescriptor();
				fi = new FileInputStream(fileDescriptor);
				fi.read(buffer);
			}
			
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(fileDescriptor!=null){
				try {
					fi.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		tv.setText(new String(buffer));
	}
 
	@Override
	protected void onDestroy() {
		unbindService(mConnection);
		mConnection = null;
		super.onDestroy();
	}
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内存映射是一种将文件映射到进程的内存空间的技术。内存映射可以通过将大文件映射到进程的虚拟地址空间,从而使得对文件的访问和操作变得更加高效。在处理超大文件读写时,内存映射(Memory Mapping)是一种常见的解决方案。 通过内存映射技术,文件可以直接映射到进程的内存空间中,从而避免了频繁的磁盘IO操作。当需要读取文件内容时,可以直接从内存中读取,而无需通过磁盘读取;当需要写入文件内容时,也可以直接在内存中进行写入,然后通过操作系统的缓存机制同步到磁盘中。这样一来,能够大大提高文件读写的效率。 内存映射超大文件的优势主要有以下几点: 1. 提高读写速度:内存映射利用了虚拟内存的机制,将磁盘文件映射到内存中,直接在内存中进行读写操作,不需要频繁的磁盘IO操作,因此能够提高读写速度。 2. 简化编程:内存映射将文件内容映射到进程的地址空间中,通过操作内存地址,可以直接访问文件内容,不需要手动进行文件的打开、关闭、读写等操作,简化了编程复杂度。 3. 节省内存空间:内存映射技术对文件进行了按需加载,只有当需要访问某一部分文件内容时,才将该部分内容加载到内存中。这种按需加载的方式避免了一次性将整个文件加载到内存中,节省了内存空间。 4. 方便并发操作:多个进程或线程可以通过共享内存映射的方式同时访问同一个文件,实现并发操作,提高了系统的并发性能。 然而,需要注意的是内存映射也有一些限制和风险,比如映射超大文件时可能会导致内存不足或虚拟内存紧张等问题。因此,在进行内存映射超大文件读写时,需要对文件的大小和内存资源进行合理评估和管理,确保系统的稳定性和性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值