LLM激活函数深度解析:从ReLU到GELU、Swish、GLU的技术演进
2026/9/7 10:39:14
🧠一句话概括:Ashmem(匿名共享内存)就像"进程间的公共黑板",多个进程可以同时读写同一块内存。
想象一个办公室场景 🏢:
普通内存:
每个员工有自己的便签本 员工A:写在自己的便签上 员工B:看不到员工A写的内容 要传递信息 → 需要复制便签共享内存:
办公室有一块公共白板 📋 员工A:在白板上写内容 员工B:直接看白板上的内容 无需复制 → 直接共享!Ashmem(Anonymous Shared Memory)是 Android/Linux 系统提供的匿名共享内存机制:
问题:每个进程有独立的内存空间,无法直接访问其他进程的内存。
| 方式 | 问题 |
|---|---|
| 管道/Socket | 需要数据复制,大数据量效率低 |
| 消息队列 | 有大小限制,需要序列化 |
| 信号 | 只能传递简单信息 |
| 优势 | 说明 |
|---|---|
| 零拷贝 | 数据无需复制,直接共享 |
| 高效 | 适合大数据量传输 |
| 灵活 | 可以设置保护标志 |
| 安全 | 支持权限控制 |
| 成员 | 类型 | 说明 |
|---|---|---|
memoryFd_ | int | 文件描述符 |
memorySize_ | int32_t | 内存区域大小 |
flag_ | int | 用户空间保护标志 |
startAddr_ | void* | 映射后的起始地址 |
// 静态工厂方法staticsptr<Ashmem>CreateAshmem(constchar*name,int32_tsize);boolMapAshmem(intmapType);// 通用映射boolMapReadAndWriteAshmem();// 读写映射boolMapReadOnlyAshmem();// 只读映射voidUnmapAshmem();// 取消映射flowchart LR subgraph 映射类型 A[MapAshmem<br/>PROT_READ] --> R[只读] B[MapAshmem<br/>PROT_WRITE] --> W[只写] C[MapAshmem<br/>PROT_READ|PROT_WRITE] --> RW[读写] endboolWriteToAshmem(constvoid*data,int32_tsize,int32_toffset);constvoid*ReadFromAshmem(int32_tsize,int32_toffset);Ashmem 内存区域: ┌────────────────────────────────────────────────────────┐ │ memorySize_ 字节 │ ├────────────────────────────────────────────────────────┤ │ startAddr_ │ │ ↓ │ │ ┌──────┬──────┬──────┬──────┬──────┬──────────────────┐│ │ │ │ │ │ │ │ ││ │ │ 数据1 │ 数据2 │ 数据3 │ ... │ 数据N │ 空闲空间 ││ │ │ │ │ │ │ │ ││ │ └──────┴──────┴──────┴──────┴──────┴──────────────────┘│ │ ↑ ↑ │ │ offset=0 offset=n │ └────────────────────────────────────────────────────────┘#include"ashmem.h"#include<iostream>#include<cstring>usingnamespaceOHOS;voidBasicAshmemDemo(){// 1. 创建 Ashmem 区域sptr<Ashmem>ashmem=Ashmem::CreateAshmem("MySharedMem",1024);if(ashmem==nullptr){std::cerr<<"创建 Ashmem 失败"<<std::endl;return;}std::cout<<"Ashmem FD: "<<ashmem->GetAshmemFd()<<std::endl;std::cout<<"Ashmem Size: "<<ashmem->GetAshmemSize()<<std::endl;// 2. 映射到用户空间(读写模式)if(!ashmem->MapReadAndWriteAshmem()){std::cerr<<"映射失败"<<std::endl;return;}// 3. 写入数据constchar*message="Hello, Ashmem!";if(ashmem->WriteToAshmem(message,strlen(message)+1,0)){std::cout<<"写入成功"<<std::endl;}// 4. 读取数据constchar*readData=static_cast<constchar*>(ashmem->ReadFromAshmem(strlen(message)+1,0));if(readData){std::cout<<"读取到: "<<readData<<std::endl;}// 5. 取消映射ashmem->UnmapAshmem();// 6. 关闭(析构时也会自动关闭)ashmem->CloseAshmem();}#include"ashmem.h"structUserData{intid;charname[32];doublescore;};voidWriteStructDemo(){sptr<Ashmem>ashmem=Ashmem::CreateAshmem("UserData",sizeof(UserData)*10);ashmem->MapReadAndWriteAshmem();// 写入多个结构体for(inti=0;i<10;i++){UserData user;user.id=i+1;snprintf(user.name,sizeof(user.name),"User%d",i+1);user.score=80.0+i*2;intoffset=i*sizeof(UserData);ashmem->WriteToAshmem(&user,sizeof(UserData),offset);}// 读取第 5 个用户intreadOffset=4*sizeof(UserData);constUserData*user5=static_cast<constUserData*>(ashmem->ReadFromAshmem(sizeof(UserData),readOffset));if(user5){std::cout<<"ID: "<<user5->id<<std::endl;std::cout<<"Name: "<<user5->name<<std::endl;std::cout<<"Score: "<<user5->score<<std::endl;}ashmem->UnmapAshmem();ashmem->CloseAshmem();}#include"ashmem.h"#include<unistd.h>voidProducerProcess(){// 创建共享内存sptr<Ashmem>ashmem=Ashmem::CreateAshmem("SharedBuffer",4096);ashmem->MapReadAndWriteAshmem();intfd=ashmem->GetAshmemFd();intsize=ashmem->GetAshmemSize();// 通过某种 IPC 方式(如 Binder)将 fd 和 size 传递给进程 B// SendToProcessB(fd, size);// 写入数据intcounter=0;while(true){charbuffer[64];snprintf(buffer,sizeof(buffer),"Message #%d",++counter);ashmem->WriteToAshmem(buffer,strlen(buffer)+1,0);std::cout<<"生产者写入: "<<buffer<<std::endl;sleep(1);}}#include"ashmem.h"#include<unistd.h>voidConsumerProcess(intfd,intsize){// 使用从进程 A 获取的 fd 创建 Ashmemsptr<Ashmem>ashmem=newAshmem(fd,size);// 只读映射ashmem->MapReadOnlyAshmem();// 读取数据while(true){constchar*data=static_cast<constchar*>(ashmem->ReadFromAshmem(64,0));if(data){std::cout<<"消费者读取: "<<data<<std::endl;}sleep(1);}}#include"ashmem.h"#include<atomic>classSharedRingBuffer{public:staticconstexprintBUFFER_SIZE=4096;staticconstexprintHEADER_SIZE=sizeof(int)*2;// head + tailSharedRingBuffer(constchar*name){ashmem_=Ashmem::CreateAshmem(name,BUFFER_SIZE+HEADER_SIZE);ashmem_->MapReadAndWriteAshmem();// 初始化头尾指针intzero=0;ashmem_->WriteToAshmem(&zero,sizeof(int),0);// headashmem_->WriteToAshmem(&zero,sizeof(int),sizeof(int));// tail}boolWrite(constvoid*data,intsize){int*head=(int*)ashmem_->ReadFromAshmem(sizeof(int),0);int*tail=(int*)ashmem_->ReadFromAshmem(sizeof(int),sizeof(int));intavailable=(BUFFER_SIZE+*head-*tail)%BUFFER_SIZE;if(size>available){returnfalse;// 缓冲区满}intwritePos=HEADER_SIZE+*tail;ashmem_->WriteToAshmem(data,size,writePos);intnewTail=(*tail+size)%BUFFER_SIZE;ashmem_->WriteToAshmem(&newTail,sizeof(int),sizeof(int));returntrue;}intRead(void*buffer,intmaxSize){int*head=(int*)ashmem_->ReadFromAshmem(sizeof(int),0);int*tail=(int*)ashmem_->ReadFromAshmem(sizeof(int),sizeof(int));intavailable=(*tail-*head+BUFFER_SIZE)%BUFFER_SIZE;intreadSize=std::min(available,maxSize);if(readSize==0){return0;}intreadPos=HEADER_SIZE+*head;constvoid*data=ashmem_->ReadFromAshmem(readSize,readPos);memcpy(buffer,data,readSize);intnewHead=(*head+readSize)%BUFFER_SIZE;ashmem_->WriteToAshmem(&newHead,sizeof(int),0);returnreadSize;}~SharedRingBuffer(){ashmem_->UnmapAshmem();ashmem_->CloseAshmem();}private:sptr<Ashmem>ashmem_;};// Linux 内存保护标志#definePROT_NONE0x0// 不可访问#definePROT_READ0x1// 可读#definePROT_WRITE0x2// 可写#definePROT_EXEC0x4// 可执行flowchart TB subgraph 内核层保护 K[SetProtection] K --> KR[PROT_READ] K --> KW[PROT_WRITE] K --> KRW[PROT_READ|PROT_WRITE] end subgraph 用户空间保护 U[MapAshmem] U --> UR[PROT_READ] U --> UW[PROT_WRITE] U --> URW[PROT_READ|PROT_WRITE] end KRW --> URW KRW --> UR KR --> UR Note1[用户空间权限 ≤ 内核层权限]| 内核层 | 用户空间 | 结果 |
|---|---|---|
| READ | READ | ✅ 可读 |
| READ | WRITE | ❌ 写入失败 |
| WRITE | WRITE | ✅ 可写 |
| WRITE | READ | ❌ 读取失败 |
| READ|WRITE | READ | ✅ 可读 |
| READ|WRITE | WRITE | ✅ 可写 |
| READ|WRITE | READ|WRITE | ✅ 可读写 |
sptr<Ashmem>ashmem=Ashmem::CreateAshmem("Protected",1024);// 设置内核层保护(只读)ashmem->SetProtection(PROT_READ);// 尝试读写映射 - 会失败,因为内核层只允许读boolsuccess=ashmem->MapReadAndWriteAshmem();// false// 只读映射 - 成功success=ashmem->MapReadOnlyAshmem();// true// 获取当前保护标志intprot=ashmem->GetProtection();// PROT_READ// 1. 使用智能指针管理sptr<Ashmem>ashmem=Ashmem::CreateAshmem("name",size);// 2. 检查创建结果if(ashmem==nullptr){// 处理错误}// 3. 检查映射结果if(!ashmem->MapReadAndWriteAshmem()){// 处理错误}// 4. 检查读写结果if(!ashmem->WriteToAshmem(data,size,offset)){// 处理错误}// 5. 使用完毕后取消映射ashmem->UnmapAshmem();// 6. 根据需要设置合适的保护标志ashmem->SetProtection(PROT_READ);// 只读共享// 错误1: 不检查返回值sptr<Ashmem>ashmem=Ashmem::CreateAshmem("name",-1);// size 无效ashmem->MapReadAndWriteAshmem();// ❌ ashmem 为 nullptr// 错误2: 越界访问ashmem->WriteToAshmem(data,1024,900);// ❌ 900 + 1024 > size// 错误3: 权限不匹配ashmem->SetProtection(PROT_READ);ashmem->MapReadAndWriteAshmem();// ❌ 映射失败// 错误4: 未映射就读写sptr<Ashmem>ashmem=Ashmem::CreateAshmem("name",1024);ashmem->WriteToAshmem(data,size,0);// ❌ 未映射// 错误5: 重复映射ashmem->MapReadAndWriteAshmem();ashmem->MapReadOnlyAshmem();// ❌ 应该先 UnmapAshmem| 场景 | 建议 |
|---|---|
| 大数据量 | 使用 Ashmem 避免复制 |
| 频繁读写 | 保持映射状态,避免反复 map/unmap |
| 多进程读 | 使用只读映射,提高安全性 |
| 对齐访问 | 按 4 字节或 8 字节对齐,提高效率 |
// 打印 Ashmem 状态voidDebugAshmem(constsptr<Ashmem>&ashmem){std::cout<<"=== Ashmem Debug ==="<<std::endl;std::cout<<"FD: "<<ashmem->GetAshmemFd()<<std::endl;std::cout<<"Size: "<<ashmem->GetAshmemSize()<<std::endl;std::cout<<"Protection: "<<ashmem->GetProtection()<<std::endl;}// 检查系统 Ashmem 使用情况// cat /proc/ashmem (如果可用)| 函数 | 说明 | 返回值 |
|---|---|---|
AshmemCreate(name, size) | 创建 Ashmem 区域 | fd |
AshmemSetProt(fd, prot) | 设置保护标志 | 0 成功,-1 失败 |
AshmemGetSize(fd) | 获取大小 | size |
| 方法 | 说明 | 返回值 |
|---|---|---|
CreateAshmem(name, size) | 创建 Ashmem | sptr |
GetAshmemFd() | 获取文件描述符 | int |
GetAshmemSize() | 获取大小 | int32_t |
SetProtection(type) | 设置保护标志 | bool |
GetProtection() | 获取保护标志 | int |
MapAshmem(mapType) | 映射内存 | bool |
MapReadAndWriteAshmem() | 读写映射 | bool |
MapReadOnlyAshmem() | 只读映射 | bool |
UnmapAshmem() | 取消映射 | void |
WriteToAshmem(data, size, offset) | 写入数据 | bool |
ReadFromAshmem(size, offset) | 读取数据 | void* |
CloseAshmem() | 关闭 | void |
| 标志 | 值 | 说明 |
|---|---|---|
PROT_NONE | 0x0 | 不可访问 |
PROT_READ | 0x1 | 可读 |
PROT_WRITE | 0x2 | 可写 |
PROT_EXEC | 0x4 | 可执行 |
记住这三点: