Android 共享内存

Parcelable 和 Serializable 区别

  • Serializable IO完成(通过磁盘文件读写)

  • Parcelable C++ 对象指针 来实现共享内存

import android.os.Parcel;
import androidx.annotation.NonNull;

public class ApiResponseBean extends Throwable implements Parcelable {

    private boolean success;
    private String msg;

    protected ApiResponseBean(Parcel in) {
        success = in.readByte() != 0;
        msg = in.readString();
    }

    public static final Creator<ApiResponseBean> CREATOR = new Creator<ApiResponseBean>() {
        @Override
        public ApiResponseBean createFromParcel(Parcel in) {
            return new ApiResponseBean(in);
        }

        @Override
        public ApiResponseBean[] newArray(int size) {
            return new ApiResponseBean[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }
    
    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(success?1:0);
        dest.writeString(msg);
    }
}

数据序列化的部分写入和读取的顺序不能乱,C++根据指针下标来读取数据;

Parcel.obtain 对象池 Handler message.obtain

  • 私有 Parcel 防止直接 new 通过 obtain 获取;
  • 单例 同步锁 对象池
    静态链表的结构 形成一个对象池;
/**
     * Retrieve a new Parcel object from the pool.
     */
    @NonNull
    public static Parcel obtain() {
        Parcel res = null;
        synchronized (sPoolSync) {
            if (sOwnedPool != null) {
                res = sOwnedPool;
                sOwnedPool = res.mPoolNext;
                res.mPoolNext = null;
                sOwnedPoolSize--;
            }
        }

        // When no cache found above, create from scratch; otherwise prepare the
        // cached object to be used
        if (res == null) {
            res = new Parcel(0);
        } else {
            if (DEBUG_RECYCLE) {
                res.mStack = new RuntimeException();
            }
            res.mReadWriteHelper = ReadWriteHelper.DEFAULT;
        }
        return res;
    }

Parcel 设计思路

在这里插入图片描述

  • nativeptr 保存底层的C++ 对象指针,为了后面反转成 C++ 对象,操作 C++ 对象功能, 是保存在 native 堆中的,不受 GC 的影响;
  • Parcel.java
  • android_os_Parcel.cpp 对应 java 类的包名
  • Parcel.cpp

共享内存

在这里插入图片描述

Parcel翻译过来是打包的意思,其实就是包装了我们需要传输的数据,然后在Binder中传输,也就是用于跨进程传输数据共享内存

简单来说,Parcel提供了一套机制,可以将序列化之后的数据写入到一个共享内存中,其他进程通过Parcel可以从这块共享内存中读出字节流,并反序列化成对象, 下图是这个过程的模型。
在这里插入图片描述

### Android共享内存的使用方法 #### 1. **匿名共享内存 (Ashmem)** Android 提供了一种基于 Linux 共享内存机制的方式——匿名共享内存(Anonymous Shared Memory, Ashmem)。这种技术允许不同进程之间共享同一块内存区域。其核心思想是通过 `/dev/ashmem` 设备文件创建一个共享内存区,并将其映射到各个进程中。 在 Native 层,可以通过 `ashmem_create_region` 和 `mmap` 系统调用来实现共享内存的操作[^3]。而在 Java 层,则主要依赖于 `MemoryFile` 或者更推荐使用的 `SharedMemory` 类来完成这一功能[^1]。 --- #### 2. **Java 层实现** ##### 使用 `SharedMemory` 类 Google 推荐开发者优先使用 `SharedMemory` 来处理共享内存需求。以下是具体实现步骤: - 创建一个新的共享内存对象。 - 将该共享内存映射至当前进程的空间。 - 如果需要跨进程访问,则需配合 Binder 或其他 IPC 方式传递句柄。 ```java import android.os.SharedMemory; public class SharedMemoryExample { public static void main(String[] args) throws Exception { // Step 1: Create a new shared memory region with size of 4KB. SharedMemory sharedMemory = SharedMemory.create("example_shared_memory", 4 * 1024); // Step 2: Map the shared memory to current process's address space. ByteBuffer buffer = sharedMemory.mapReadWrite(); // Write data into the mapped buffer. buffer.put(0, (byte)'H'); buffer.put(1, (byte)'i'); System.out.println("Data written successfully."); // Unmap and close when done. sharedMemory.close(); } } ``` 此代码片段展示了如何利用 `SharedMemory` 创建一块大小为 4 KB 的共享内存区域,并向其中写入数据[^1]。 --- ##### 使用 `MemoryFile` 尽管 Google 更倾向于推广 `SharedMemory`,但在某些场景下仍可考虑使用 `MemoryFile`。需要注意的是,`MemoryFile` 实际上也是对底层 ashmem 的封装[^2]。 ```java import android.media.MemoryFile; import java.io.IOException; public class MemoryFileExample { public static void main(String[] args) throws IOException { int fileSize = 4 * 1024; // Size in bytes. // Step 1: Initialize a new MemoryFile instance. MemoryFile memoryFile = new MemoryFile("memory_file_example", fileSize); byte[] dataArray = { 'T', 'e', 's', 't' }; // Step 2: Write some test data into it. memoryFile.writeBytes(dataArray, 0, 0, dataArray.length); // Read back from the file for verification purposes. byte[] readBuffer = new byte[dataArray.length]; memoryFile.readBytes(readBuffer, 0, 0, readBuffer.length); String resultString = new String(readBuffer); System.out.println("Read Data: " + resultString); // Close resources after usage. memoryFile.close(); } } ``` 虽然 `MemoryFile` 可以满足基本需求,但由于其实现细节较为复杂且不够直观,因此官方文档建议尽量采用更为现代化的解决方案如 `SharedMemory`[^2]。 --- #### 3. **Native 层实现** 对于性能敏感的应用程序来说,在 C/C++ 中直接操作 ashmem 能够获得更高的效率。下面是一个简单的示例演示如何在原生环境中设置和读取共享内存的内容。 ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #define SHM_NAME "/test_ashmem" #define SIZE 4096 int main() { const char* message = "Hello from native!"; // Open or create an anonymous shared memory area. int fd = open("/dev/ashmem", O_RDWR); if (ioctl(fd, ASHMEM_SET_SIZE, SIZE)) { perror("Failed to set size"); exit(EXIT_FAILURE); } // Map this memory segment into our own virtual address space. void* ptr = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) { perror("Mapping failed!"); close(fd); return EXIT_FAILURE; } // Store string inside allocated block. memcpy(ptr, message, strlen(message)); printf("Message stored at %p\n", ptr); munmap(ptr, SIZE); // Clean up mapping before exiting program. close(fd); return EXIT_SUCCESS; } ``` 这里展示了一个完整的流程:从打开设备节点到分配特定尺寸的缓冲区再到最终的数据存储过程[^3]。 --- ### 总结 无论是通过高级别的 API (`SharedMemory`) 还是在较低层次上的手动控制 (C/C++) ,都可以有效地达成 Android 平台下的共享内存目标。每种方案都有各自适用范围以及优缺点;选择合适的技术栈取决于项目具体情况和个人偏好等因素影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值