Android MemoryFile 共享内存

这篇具有很好参考价值的文章主要介绍了Android MemoryFile 共享内存。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

应用场景:

跨进程传输大数据,如文件、图片等;

技术选型:

共享内存–MemoryFile;

优点:

1. 共享内存没有传输大小限制,所以和应用总的分配内存一样(512MB);
2. MemoryFile 是对 SharedMemory 的包装,使用简单便于管理;

实现步骤:

(以A进程共享文件a.txt给B进程为例)

A进程: 创建共享内存空间工具类
 
public class ShareMemoryUtils {

    private static ParcelFileDescriptor getPfdFromMemoryFile(final String name, final byte[] bytes) {
        ParcelFileDescriptor pfd = null;
        try {
                    long startTime = System.currentTimeMillis();
                    MemoryFile memoryFile = null;
                    try {
                        memoryFile = new MemoryFile(name, bytes.length);
                        memoryFile.allowPurging(true);
                        memoryFile.writeBytes(bytes, 0, 0, bytes.length);
                        pfd = getParcelFileDescriptor(memoryFile);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        closeMemoryFile(memoryFile, null);
                    }
                }
            });
        }
        return pfd;
    }

    private static ParcelFileDescriptor getParcelFileDescriptor(MemoryFile memoryFile) {
        try {
            Method method = MemoryFile.class.getDeclaredMethod("getFileDescriptor");
            method.setAccessible(true);
            FileDescriptor fd = (FileDescriptor) method.invoke(memoryFile);
            return ParcelFileDescriptor.dup(fd);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private static void closeMemoryFile(MemoryFile memoryFile, ParcelFileDescriptor pfd) {
        if (pfd != null) {
            try {
                pfd.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (memoryFile != null) {
            memoryFile.close();
        }
    }

}
A进程:创建aidl接口,使用binder接口传递文件描述符
interface IMemoryFileApi {
    ParcelFileDescriptor getParcelFileDescriptor(String type, String params);
    boolean setParcelFileDescriptor(String type, in ParcelFileDescriptor pfd, String params);
    oneway void releaseParcelFileDescriptor(String type);
}
B进程:通过bindService连接到A进程,并调用aidl接口获取文件描述符
/**
     * 通过 binder 接口获取远程进程共享内存的文件描述符
     */
    private ParcelFileDescriptor getParcelFileDescriptor() {
        try {
            if (iMemoryFileApi != null) {
                ParcelFileDescriptor pfd = iMemoryFileApi.getParcelFileDescriptor();
                return pfd;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
B进程:通过文件描述符读取数据流即可;

注意:

文件描述符在每个进程都有副本,A进程的文件描述符被B进程接收后,实际上已经有了两份文件描述符,即两个进程有各自的内存映射空间。所以B进程读取数据流之后,除了要关闭自己进程的文件描述符对象之外,还要调用接口关闭A进程中的文件描述符;
B进程想要把修改后的文件数据回写给A进程时,需要做的操作和A进程的操作是完全一样的,把文件数据重新创建共享内存,再把文件描述符通过binder接口传递给A进程即可;

总结

网上很多时间比较久的贴子,通过各种反射在A进程获取MemoryFIle来读取共享数据,这种方式并不可取;MemoryFile新版本的封装方式就体现了它的使用方式,Google是希望随时使用随时创建MemoryFile并把文件描述附共享出去这种方式来实现功能的。


android MemoryFile内存共享

进程之间传递数据,由于Binder传递数据有限制1M,所以如果遇到大的数据传递的时候就需要使用使用到MemoryFile内存共享来解决,最合适不过了

首先,MemoryFile是基于Binder自带的transact方法进行传输数据的,因此直接继承Binder即可,不过一般项目中免不了传递一些基本数据类型或者bean数据,因此一般结合aidl一起使用。

android aidl使用记录

  • 服务端处理数据

    private byte[] buffer = new byte[1024];
	//public class MyBinder extends IRtcService.Stub {
    public class MyBinder extends Binder {
		//此方法Binder自带
        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            LogUtil.e("接收到远端调用" + "code" + code);
            if (code == 100) {
                try {
                    ParcelFileDescriptor pfd = data.readParcelable(null);
                    // 或者
//                    ParcelFileDescriptor pfd = data.readFileDescriptor();
                    FileDescriptor fileDescriptor = pfd.getFileDescriptor();
                    FileInputStream fi = new FileInputStream(fileDescriptor);
                    fi.read(buffer);
                    fi.close();
                    LogUtil.e("--->" + new String(buffer).replace("\0", ""));

                    //返回给客户端
                    reply.writeString("服务器接受数据成功");
                    reply.writeInt(200);
                    return true;
                } catch (IOException e) {
                    e.printStackTrace();
                }


            }
            return super.onTransact(code, data, reply, flags);
        }

    }
  • 客户端

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        try {
                /**
                 *
                 */
                // 参数1文件名,可为null,参数2文件长度
                mMemoryFile = new MemoryFile(null, 1024);
                //在设置了allowPurging为false之后,这个MemoryFile对应的Ashmem就会被标记成"pin",
                // 那么即使在android系统内存不足的时候,也不会对这段内存进行回收
                mMemoryFile.allowPurging(false);
                android.os.Parcel data = android.os.Parcel.obtain();
                android.os.Parcel reply = android.os.Parcel.obtain();

                byte[] buffer = "31283216382163812362183621832163812".getBytes();
                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);

                    //写入数据,对应服务端用data.readParcelable(null)接收数据
                    data.writeParcelable(pfd, 0);
                    // 或者,对应服务端用data.readFileDescriptor()接收数据
//                    data.writeFileDescriptor(fileDescriptor);
                    /**
                     * code 是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法;
                     * data客户端传递过来的参数;
                     * replay服务器返回回去的值;
                     * flags标明是否有返回值,0为有(双向),1为没有(单向)。
                     */
                    service.transact(100, data, reply, 0);

                    //服务器返回的值
                    String message = reply.readString();
                    LogUtil.e("--message--->" + message);
                    int code = reply.readInt();
                    LogUtil.e("--code--->" + code);
                    if (code==200){
                    	data.recycle();
                        reply.recycle();
                        mMemoryFile.close();
                        mMemoryFile=null;
                    }

                }


            } catch (RemoteException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            if (mConnection != null) {
                try {
                    iRtcService = null;
                    unbindService(mConnection);
                } catch (Exception e) {

                }
            }
        }
    };
  • 结果

    客户端

03-15 21:16:36.011 4327-4327/com.fuyao.elf_android_remote E/elf_remote: --message--->服务器接受数据成功
03-15 21:16:36.011 4327-4327/com.fuyao.elf_android_remote E/elf_remote: --code--->200

 服务端

03-15 21:16:36.010 4300-4313/com.fuyao.elf_android_center:rtc_remote E/elf_center: 接收到远端调用code100
03-15 21:16:36.010 4300-4313/com.fuyao.elf_android_center:rtc_remote E/elf_center: --->31283216382163812362183621832163812

Android内存映射文件实现

1. 什么是内存映射文件

内存映射文件是一种将磁盘上的文件映射到内存中的方法。通过内存映射文件,可以将文件的内容直接映射到内存中的一个地址空间,从而可以直接对内存进行读写操作,而无需通过传统的文件IO操作。

在Android开发中,内存映射文件常常用于处理大文件或者需要频繁读写的文件,因为通过内存映射文件可以获得更高的IO性能。

2. Android内存映射文件的实现方式

Android提供了MemoryFile类来实现内存映射文件的功能。MemoryFile是一个基于共享内存的IPC(进程间通信)机制,它允许一个进程将一个内存映射文件映射到另一个进程的地址空间中。

下面是一个简单的代码示例,演示了如何使用MemoryFile实现内存映射文件:

// 创建一个内存映射文件
MemoryFile memoryFile = new MemoryFile("test", 1024);

// 向内存映射文件写入数据
String data = "Hello, MemoryFile!";
byte[] buffer = data.getBytes();
memoryFile.writeBytes(buffer, 0, 0, buffer.length);

// 从内存映射文件读取数据
byte[] readBuffer = new byte[buffer.length];
memoryFile.readBytes(readBuffer, 0, 0, readBuffer.length);
String readData = new String(readBuffer);

// 打印读取的数据
System.out.println(readData);

// 释放内存映射文件
memoryFile.close();


在上面的代码中,首先我们创建了一个大小为1024字节的内存映射文件。然后,我们向内存映射文件写入了字符串数据,接着又从内存映射文件中读取了数据,并将其转换为字符串。最后,我们释放了内存映射文件。

需要注意的是,MemoryFile类只能在同一个进程的不同线程之间进行通信,如果需要在不同进程之间通信,则需要使用其他的IPC机制,比如Binder。

3. 内存映射文件的优势和应用场景


内存映射文件相比于传统的文件IO操作有如下优势:

  • 更高的IO性能:由于内存映射文件将文件内容映射到内存中,所以可以避免频繁的磁盘IO操作,从而获得更高的IO性能。
  • 更低的内存占用:内存映射文件只将文件的部分或全部内容映射到内存中,而不是将整个文件加载到内存中,所以可以减少内存的占用。
  • 更方便的数据访问:通过内存映射文件,可以直接对内存中的数据进行读写操作,而无需通过文件IO相关的API,从而简化了数据访问的操作。

内存映射文件常常应用于以下场景:

  • 大文件处理:当需要处理大文件时,通过内存映射文件可以获得更高的IO性能。
  • 频繁读写文件:当需要频繁读写文件时,通过内存映射文件可以避免频繁的磁盘IO操作,提高程序的响应速度。
  • 进程间通信:通过内存映射文件可以在同一个进程的不同线程之间进行通信。

4. 总结

本文介绍了Android内存映射文件的实现方式以及其优势和应用场景。通过内存映射文件,我们可以获得更高的IO性能和更方便的数据访问方式。在处理大文件或者需要频繁读写文件的场景下,使用内存映射文件可以提高程序的性能和响应速度。
 文章来源地址https://www.toymoban.com/news/detail-828256.html

到了这里,关于Android MemoryFile 共享内存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android adb shell 查看App内存(java堆内存/vss虚拟内存/详细的内存状况/内存快照hprof)和系统可用内存

    1.adb shell 获取app 进程的pid 根据某个渠道包,去查询对应的pid,如下所示: 2.通过adb shell 查看设备的java dalvik 堆内存的最大值 执行命令行: 若是app进程中java heap(dalvik heap size) 堆内存超过384m 就会抛出oom. 若是app mainfest.xml 中设置了largeHeap=“true”,则app 进程dalvik heap limit 对应

    2024年02月15日
    浏览(57)
  • Java安全之servlet内存马分析

    目录 前言  什么是中间键 了解jsp的本质 理解servlet运行机制 servlet的生命周期 Tomcat总体架构  查看Context 的源码 servlet内存马实现 参考 前言  php和jsp一句话马我想大家都知道,早先就听小伙伴说过一句话木马已经过时了,现在是内存马的天下了 ,内存马无落地文件,更隐蔽

    2024年02月04日
    浏览(38)
  • Java扩展Nginx之七:共享内存

    这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 作为《Java扩展Nginx》系列的第七篇,咱们来了解一个实用工具 共享内存 ,正式开始之前先来看一个问题 在一台电脑上,nginx开启了多个worker,如下图,如果此时我们用了nginx-clojure,就相当于有了四

    2024年02月16日
    浏览(36)
  • Android不同APP之间共享数据的方式

    今天给大家介绍三种不同APP之间共享数据的方式 第一种:使用SharePreference 使用SharePreference共享数据 第二种:使用ContentProvider, 这个就不仔细讲了,大家看看其他文章吧 第三种:sharedUserId 通过SharedUser id,拥有同一个User id的多个APK可以配置成运行在同一个进程中.所以默认就是

    2024年02月10日
    浏览(50)
  • Android之内存泄漏与内存溢出

    内存泄漏(memory leak):是指程序在申请内存后,无法释放已申请的内存空间,导致系统无法及时回收内存并且分配给其他进程使用。通常少次数的内存无法及时回收并不会到程序造成什么影响,但是如果在内存本身就比较少获取多次导致内存无法正常回收时,就会导致内存

    2024年02月13日
    浏览(48)
  • Android内存泄漏分析及检测工具LeakCanary简介,Android进阶

    @Synchronized override fun expectWeaklyReachable( watchedObject: Any, description: String ) { if (!isEnabled()) { return } removeWeaklyReachableObjects() val key = UUID.randomUUID() .toString() val watchUptimeMillis = clock.uptimeMillis() val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue) SharkLog.d { \\\"Watching \\\" +

    2024年04月25日
    浏览(39)
  • Android设备通过USB共享网络给OpenWrt路由器

    1️⃣前言 如果随身WiFi自带的热点不稳定的话,可以考虑插到有USB口的OpenWrt路由器上,减少随身WiFi的负荷,使网络更为稳定。 但有的路由器虽然有USB口,也是OpenWrt系统,连接设备后却没网。 这篇图文就分享一下如何设置才能让OpenWrt路由器通过USB共享Android设备(如Android方

    2024年02月09日
    浏览(56)
  • 【Android 性能优化:内存篇】——WebView 内存泄露治理

    背景:笔者在公司项目中优化内存泄露时发现WebView 相关的内存泄露问题非常经典,一个 Fragment 页面使用的 WebView 有多条泄露路径,故记录下。 项目中一个Fragment 使用 Webview,在 Fragment onDestroyView 时候却没有释放,释放 WebView 还不简单嘛,于是笔者在 Fragment 的 onDestroyView 补充

    2024年02月04日
    浏览(44)
  • android 如何分析应用的内存(十七)——使用MAT查看Android堆

    前一篇文章,介绍了使用Android profiler中的memory profiler来查看Android的堆情况。 如Android 堆中有哪些对象,这些对象的引用情况是什么样子的。 可是我们依然面临一个比较严峻的挑战:不管是app开发者,还是内存分析者而言,堆中的对象,非常之多,不仅有Android 原生的类,还

    2024年02月13日
    浏览(69)
  • Android中的内存管理

    1.内存管理机制概述 1.分配机制: 安卓系统会为每个进程合理的分配内存,从而保证每个进程能正常运行。而不至于内存不够使用或者每个进程占用太多的内存。 2.回收机制 操作系统在内存不足的时候,它会有一个合理的回收和再分配的机制。 从而保证新的进程能够正常运

    2024年02月07日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包