面试题答案
一键面试架构设计思路
- 独立内存池:每个工作线程拥有自己独立的内存池,用于频繁的小内存分配,减少内存碎片并提高分配效率。主线程不参与具体的小内存分配,但可以负责初始化内存池。
- 共享内存数据管理:对于工作线程间偶尔需要共享的部分内存数据,采用共享内存区域进行管理,并通过同步机制保证数据一致性。
- 分层设计:将内存管理分为内存池管理层和共享内存管理层,使架构更清晰,便于维护和扩展。
关键数据结构
- 内存池数据结构
- 内存块链表:每个内存池维护一个空闲内存块链表,用于存储可分配的内存块。链表节点包含指向下一个节点的指针和内存块大小信息。
typedef struct MemoryBlock { struct MemoryBlock* next; size_t size; } MemoryBlock; typedef struct ThreadMemoryPool { MemoryBlock* freeList; } ThreadMemoryPool;
- 内存池控制块:用于管理整个内存池,记录内存池的总大小、已分配大小等信息。
typedef struct ThreadMemoryPoolControl { ThreadMemoryPool pool; size_t totalSize; size_t allocatedSize; } ThreadMemoryPoolControl;
- 共享内存数据结构
- 共享内存头:记录共享内存区域的大小、使用状态等信息。
typedef struct SharedMemoryHeader { size_t size; int isInUse; } SharedMemoryHeader; typedef struct SharedMemory { SharedMemoryHeader header; char data[]; } SharedMemory;
同步机制
- 线程锁:对于每个内存池的空闲链表操作,使用互斥锁(
pthread_mutex_t
)来保证线程安全。在分配和释放内存块时,获取锁,操作完成后释放锁。pthread_mutex_t poolMutex; pthread_mutex_init(&poolMutex, NULL); // 分配内存时 pthread_mutex_lock(&poolMutex); // 从空闲链表分配内存块操作 pthread_mutex_unlock(&poolMutex);
- 读写锁:对于共享内存数据,采用读写锁(
pthread_rwlock_t
)。当工作线程读取共享内存数据时,获取读锁;当需要修改共享内存数据时,获取写锁。这样可以允许多个线程同时读,但只允许一个线程写,保证数据一致性。pthread_rwlock_t sharedMemoryLock; pthread_rwlock_init(&sharedMemoryLock, NULL); // 读操作 pthread_rwlock_rdlock(&sharedMemoryLock); // 读共享内存数据操作 pthread_rwlock_unlock(&sharedMemoryLock); // 写操作 pthread_rwlock_wrlock(&sharedMemoryLock); // 写共享内存数据操作 pthread_rwlock_unlock(&sharedMemoryLock);
高并发场景下的性能表现
- 优点
- 高效内存使用:独立内存池减少了内存碎片,提高了小内存分配的效率。每个线程的内存池独立管理,减少了内存分配的竞争。
- 线程安全:通过互斥锁和读写锁等同步机制,保证了内存操作的线程安全,数据一致性得到保障。
- 读性能:在高并发读场景下,由于读写锁允许并发读操作,读性能较高。
- 缺点
- 写性能:在高并发写场景下,由于写操作需要获取写锁,同一时间只允许一个线程写,可能会导致写操作的性能瓶颈。
- 锁竞争:虽然每个内存池有独立的锁,但在高并发情况下,锁竞争仍然可能存在,尤其是在频繁分配和释放内存时,会影响整体性能。可通过优化锁粒度或采用无锁数据结构来进一步提升性能。