美文网首页
ndk开发—mmap技术手写实现高性能日志库

ndk开发—mmap技术手写实现高性能日志库

作者: Peakmain | 来源:发表于2021-07-08 11:38 被阅读0次

基础知识

类型转换

c语言风格的类型转换

  • (type)expression
  • type(expression)

c++中有4个类型转换符

  • static_cast
    • 对比dynamic_cast缺少运行时检测
    • 不能交叉转换(不是同一继承体系的,无法转换)
    • 常用于基本数据类型的转换、非const转成const
  • dynamic_cast
    • 一般用于多态(virutal)类型的转换,有运行时安全检测
    • 和(type)expression不一样,多了运行时安全检测
    • 如果安全则将值直接返回,如果不安全则返回null
  • reinterpret_cast
    • 属于比较底层的强制转换,没有任何类型检测和格式转换,仅仅是简单的二进制数据拷贝
#include <iostream>
using namespace std;
#pragma warning(disable:4996)


int main() {
    //0A 00 00 00
    int a =10;
    //00 00 00 00 00 00 24 40
    //double d=a;
    //0A 00 00 00 cc cc cc cc
    double d = reinterpret_cast<double&>(a);
    cout << sizeof(a) << endl;
    cout << sizeof(d) << endl;
    getchar();
    return 1;
}
  • const_cast
    • 一般用于去除const属性,将const转成非const
    • 和(type)expression一模一样

使用格式

  • xx_cast<type>(expression)

  • Linux系统分配真正内存时,用页作为单位,一次最少提供一页的真实内存空间
  • 方法
//头文件
#include <unistd.h>
//函数,返回值是内存分页大小
static __inline__ int getpagesize(void) {
  return sysconf(_SC_PAGESIZE);
}

memcpy

  • 函数
void *memcpy(void *str1, const void *str2, size_t n)
  • 参数
    • str1:用于存储复制内容的目标
    • str2:要复制的数据源
    • n:要被复制的字节数

通俗讲:将str2的n个数据复制给str1

mmap

  • 函数
 void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t of    fset); 
  • 参数

    • add:地址,当为NULL的时候,由系统分配
    • len:内存的大小
    • prot:
      • PROT_EXEC内容可以被执行;
      • PROT_READ:内容可以被读取;
      • PROT_WRITE:内容可以被写入;
      • PROT_NONE:内容不可访问
    • flags:MAP_SHARED:共享;MAP_PRIVATE:私用;MAP_ANONYMOUS:匿名映射(不基于文件),fd传入-1
    • fd:打开文件的句柄
    • fset:偏移大小,必须是4k的整数倍,一个物理页映射是4k
  • 原理
    通过mmap映射文件的一块到用户空间,然后通过mmap返回的指针操作mmap映射的用户空间,相当于同时操作了文件

实现步骤

  • 1、通过mmap获取到文件的句柄
/**
 * 默认最小的增长大小
 */
static int DEFAULT_INCREASE_SIZE = getpagesize() * 128;

FileLogger::FileLogger(const char *logPath, int maxFileSize) {
    this->logPath = (char *) malloc(strlen(logPath) + 1);
    memcpy(this->logPath, logPath, strlen(logPath) + 1);

    this->maxFileSize = maxFileSize;
    // 计算每次映射多大数据
    increaseSize = maxFileSize / REMMAP_TIMES;

    if (mmapSize < DEFAULT_INCREASE_SIZE) {
        increaseSize = DEFAULT_INCREASE_SIZE;
    } else if (increaseSize % getpagesize() != 0) {
        // 保证是页的整数倍
        increaseSize = (increaseSize / getpagesize() + 1) * getpagesize();
    }

    // 读取到整个文件的大小
    int fileSize = getLogFileSize();

    if (fileSize <= 0) {
        mmapSize = increaseSize;
        // 打开映射文件
        mmapFile(0, mmapSize);
    } else {
        mmapSize = fileSize;
        mmapFile(0, fileSize);
        if (dataPos >= maxFileSize) {
            // 释放之前映射过的内存
            if (mmapPtr != NULL) {
                munmap(mmapPtr, mmapSize);
            }
        }
    }
}
void FileLogger::mmapFile(int start, int end) {
    // 打开文件
    int logFd = open(logPath, O_RDWR | O_CREAT, S_IRWXU);
    // 给文件新增大小空间
    ftruncate(logFd, mmapSize);
    int size = end - start;
    mmapPtr = (char *) mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, logFd, start);
    // 关闭文件
    close(logFd);
}
  • 2、获取文件的大小
int FileLogger::getLogFileSize() {
   //1、打开文件
    FILE *fp = fopen(logPath, "r");
    if (fp == NULL) {
        return 0;
    }
    fseek(fp, 0L, SEEK_END);
     //2、获取文件大小
    int size = ftell(fp);
    //3、关闭文件
    fclose(fp);
    return size;
}
  • 3、析构函数:释放映射过得内存
FileLogger::~FileLogger() {
    // 释放映射过的内存
    if (mmapPtr != NULL) {
        munmap(mmapPtr, mmapSize);
    }
}
  • 4、写文件
void FileLogger::writeData(const char *data, int dataLen) {
    if (dataPos + dataLen > mmapSize) {
        if (dataPos + dataLen > maxFileSize) {
            int maxSize = dataPos + dataLen;
            if (maxSize % getpagesize() != 0) {
                maxSize = ((maxSize / getpagesize()) + 1) * getpagesize();
            }
            increaseSize = maxSize - mmapSize;
        }

        // 释放之前映射过的内存
        if (mmapPtr != NULL) {
            munmap(mmapPtr, mmapSize);
        }
        mmapSize += increaseSize;
        mmapFile(0, mmapSize);
    }

    // 把数据写入映射区域 (文件)
    memcpy(mmapPtr + dataPos, data, dataLen);
    dataPos += dataLen;
    // memcpy(mmapPtr + (mmapSize - DEFAULT_POSITION_SIZE - 1), &dataPos, DEFAULT_POSITION_SIZE);
}
  • 5、文件读取
 FileLogger *fileLogger = (FileLogger *) nativePtr;
    if (fileLogger != NULL) {
        char *mmapPtr = fileLogger->readLog();
        jstring data=env->NewStringUTF(mmapPtr);
        return data;
    }

相关文章

网友评论

      本文标题:ndk开发—mmap技术手写实现高性能日志库

      本文链接:https://www.haomeiwen.com/subject/tahaultx.html