写信给 ashmem / 为什么 android 免费 ashmem?
Writing to ashmem / why does android free ashmem?
我想在两个 (ndk-) 进程之间共享数据。为此,我使用 ashmem 使用此 source.
一个进程连续读取(read_mem
),一个进程写入一次(write_mem
)。
问题是读取进程没有获取写入程序的值。
AND
通过查看 reader 的地图,我发现 android 会在 ashmem_create_region
之后立即删除共享内存文件。
read_mem.c
// read_mem.c
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include "ashmem.h"
#define SHM_NAME "test_mem"
int main(int argc, char **argv) {
int shID = ashmem_create_region(SHM_NAME, 2);
if (shID < 0)
{
perror("ashmem_create_region failed\n");
return 1;
}
// right here /dev/ashmem/test_mem is deleted
printf("ashmem_create_region: %d\n", shID);
char *sh_buffer = (char*)mmap(NULL, 2, PROT_READ | PROT_WRITE, MAP_SHARED, shID, 0);
if (sh_buffer == (char*)-1)
{
perror("mmap failed");
return 1;
}
printf("PID=%d", getpid());
do
{
printf("VALUE = 0x%x\n", sh_buffer[0]);
}
while (getchar());
return 0;
}
write_mem.c
// write_mem.c
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include "ashmem.h"
#define SHM_NAME "test_mem"
int main(int argc, char **argv) {
int shID = ashmem_create_region(SHM_NAME, 2);
if (shID < 0)
{
perror("ashmem_create_region failed\n");
return 1;
}
printf("ashmem_create_region: %d\n", shID);
char *sh_buffer = (char*)mmap(NULL, 2, PROT_READ | PROT_WRITE, MAP_SHARED, shID, 0);
if (sh_buffer == (char*)-1)
{
perror("mmap failed");
return 1;
}
printf("PID=%d\n", getpid());
int ch = getchar();
sh_buffer[0] = ch;
printf("Written 0x%x\n", ch);
munmap(sh_buffer, 2);
close(shID);
return 0;
}
这是输出:
读书
130|shell@mako:/data/local/tmp $ ./read_mem
ashmem_create_region: 3
PID=29655
VALUE = 0x0
写作
shell@mako:/data/local/tmp $ ./write_mem
ashmem_create_region: 3
PID=29691
A
Written 0x41
再次阅读VALUE = 0x0
(按return)
正在观看 reader 的地图:
shell@mako:/ $ cat /proc/29655/maps | grep test_mem
b6ef5000-b6ef6000 rw-s 00000000 00:04 116213 /dev/ashmem/test_mem (deleted)
如您所见 test_mem
已删除 WHILE read_mem
还活着。
其他信息
两个文件都使用android ndk-build
命令编译为可执行文件
设备:LG Nexus 4 (AOSP Lollypop)
我检查了 /dev/ashmem
它存在。
ashmem 取自 here
Ashmem 在 Linux 上不像常规共享内存那样工作,这是有充分理由的。
首先,让我们尝试解释一下“(deleted)”部分,这是内核如何实现ashmem的一个实现细节。它真正的意思是在 /dev/ashmem/ 目录中创建了一个 file entry,然后 removed,但是相应的 i-node 仍然存在,因为至少有一个打开的文件描述符。
您实际上可以创建多个具有相同名称的 ashmem 区域,它们都将显示为“/dev/ashmem/<名称>(已删除)”,但它们中的每一个都对应于不同的 i-节点,因此 different memory region。如果您在 /dev/ashmem/ 下查看,您会发现该目录仍然是空的。
这就是为什么 ashmem 区域的名称实际上只用于调试的原因。无法按名称 'open' 现有区域。
当最后一个文件描述符关闭时,ashmem i 节点和相应的内存会自动回收。这很有用,因为这意味着如果您的进程因崩溃而死亡,内核将自动回收内存。这不是常规 SysV 共享内存的情况(崩溃进程只会泄漏内存!在像 Android 这样的嵌入式系统上是不可接受的)。
您的测试程序创建了两个具有相同名称的不同 ashmem 区域,这就是为什么它们不能像您认为的那样工作。你需要的是:
1) 在其中一个进程中创建单个 ashmem 区域。
2) 将一个新的文件描述符传递给从第一个进程到第二个进程的区域。
一种方法是分叉第一个进程来创建第二个进程(这将自动复制文件描述符),但这在 Android 下通常不是一个好主意。
更好的替代方法是使用 sendmsg() 和 recvmsg() 通过两个进程之间的 Unix 域套接字发送文件描述符。这通常很棘手,但作为示例,请查看以下为 NDK 编写的源文件中的 SendFd() 和 ReceiveFd() 函数:
瞧,希望这对你有帮助
我想在两个 (ndk-) 进程之间共享数据。为此,我使用 ashmem 使用此 source.
一个进程连续读取(read_mem
),一个进程写入一次(write_mem
)。
问题是读取进程没有获取写入程序的值。
AND
通过查看 reader 的地图,我发现 android 会在 ashmem_create_region
之后立即删除共享内存文件。
read_mem.c
// read_mem.c
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include "ashmem.h"
#define SHM_NAME "test_mem"
int main(int argc, char **argv) {
int shID = ashmem_create_region(SHM_NAME, 2);
if (shID < 0)
{
perror("ashmem_create_region failed\n");
return 1;
}
// right here /dev/ashmem/test_mem is deleted
printf("ashmem_create_region: %d\n", shID);
char *sh_buffer = (char*)mmap(NULL, 2, PROT_READ | PROT_WRITE, MAP_SHARED, shID, 0);
if (sh_buffer == (char*)-1)
{
perror("mmap failed");
return 1;
}
printf("PID=%d", getpid());
do
{
printf("VALUE = 0x%x\n", sh_buffer[0]);
}
while (getchar());
return 0;
}
write_mem.c
// write_mem.c
#include <stdio.h>
#include <errno.h>
#include <sys/mman.h>
#include "ashmem.h"
#define SHM_NAME "test_mem"
int main(int argc, char **argv) {
int shID = ashmem_create_region(SHM_NAME, 2);
if (shID < 0)
{
perror("ashmem_create_region failed\n");
return 1;
}
printf("ashmem_create_region: %d\n", shID);
char *sh_buffer = (char*)mmap(NULL, 2, PROT_READ | PROT_WRITE, MAP_SHARED, shID, 0);
if (sh_buffer == (char*)-1)
{
perror("mmap failed");
return 1;
}
printf("PID=%d\n", getpid());
int ch = getchar();
sh_buffer[0] = ch;
printf("Written 0x%x\n", ch);
munmap(sh_buffer, 2);
close(shID);
return 0;
}
这是输出:
读书
130|shell@mako:/data/local/tmp $ ./read_mem
ashmem_create_region: 3
PID=29655
VALUE = 0x0
写作
shell@mako:/data/local/tmp $ ./write_mem
ashmem_create_region: 3
PID=29691
A
Written 0x41
再次阅读VALUE = 0x0
(按return)
正在观看 reader 的地图:
shell@mako:/ $ cat /proc/29655/maps | grep test_mem
b6ef5000-b6ef6000 rw-s 00000000 00:04 116213 /dev/ashmem/test_mem (deleted)
如您所见 test_mem
已删除 WHILE read_mem
还活着。
其他信息
两个文件都使用android ndk-build
命令编译为可执行文件
设备:LG Nexus 4 (AOSP Lollypop)
我检查了 /dev/ashmem
它存在。
ashmem 取自 here
Ashmem 在 Linux 上不像常规共享内存那样工作,这是有充分理由的。
首先,让我们尝试解释一下“(deleted)”部分,这是内核如何实现ashmem的一个实现细节。它真正的意思是在 /dev/ashmem/ 目录中创建了一个 file entry,然后 removed,但是相应的 i-node 仍然存在,因为至少有一个打开的文件描述符。
您实际上可以创建多个具有相同名称的 ashmem 区域,它们都将显示为“/dev/ashmem/<名称>(已删除)”,但它们中的每一个都对应于不同的 i-节点,因此 different memory region。如果您在 /dev/ashmem/ 下查看,您会发现该目录仍然是空的。
这就是为什么 ashmem 区域的名称实际上只用于调试的原因。无法按名称 'open' 现有区域。
当最后一个文件描述符关闭时,ashmem i 节点和相应的内存会自动回收。这很有用,因为这意味着如果您的进程因崩溃而死亡,内核将自动回收内存。这不是常规 SysV 共享内存的情况(崩溃进程只会泄漏内存!在像 Android 这样的嵌入式系统上是不可接受的)。
您的测试程序创建了两个具有相同名称的不同 ashmem 区域,这就是为什么它们不能像您认为的那样工作。你需要的是:
1) 在其中一个进程中创建单个 ashmem 区域。
2) 将一个新的文件描述符传递给从第一个进程到第二个进程的区域。
一种方法是分叉第一个进程来创建第二个进程(这将自动复制文件描述符),但这在 Android 下通常不是一个好主意。
更好的替代方法是使用 sendmsg() 和 recvmsg() 通过两个进程之间的 Unix 域套接字发送文件描述符。这通常很棘手,但作为示例,请查看以下为 NDK 编写的源文件中的 SendFd() 和 ReceiveFd() 函数:
瞧,希望这对你有帮助