zram压缩机制看swapon系统调用

性能优化——ZRAM [FAQ21507]zram 原理及其配置 [DESCRIPTION] swap分区其实就是 zram 部分的内容,两个可以认为是相同的东西 其中swappiness 管理的是什么情况下放入到swap 分区, 而 zram 管理了这个分区,包括分区的大小、压缩算法等 [SOLUTION] 1. 是否开机zram 方法有两个: 方法一 : CONFIG_ZSMALLOC=... 阅读详情
1.swapon开启zram交换分区
swapon /dev/block/zram0
mkswap /dev/block/zram0

上面命令调用了linux的swapon系统调用启动zram0交换分区;mkswap命令向块设备文件/dev/block/zram0写入了swap_header信息

问题:实际安卓平台是哪里触发swapon和mkswap调用的,我们已MTK8195平台为例:

init.xxx.rc:
    swapon_all /vendor/etc/fstab.enableswap

其中fstab.enableswap内容如下:
/dev/block/zram0 none swap defaults zramsize=xx%

 那么swapon_all命令执行了哪里的代码呢?又是哪里解析fstab.enableswap文件呢,答案是:

system/core/init/builtins.cpp:


/* swapon_all [ <fstab> ] */
static Result<void> do_swapon_all(const BuiltinArguments& args) {
    auto swapon_all = ParseSwaponAll(args.args);
    if (!swapon_all.ok()) return swapon_all.error();

    Fstab fstab;
    if (swapon_all->empty()) {
        if (!ReadDefaultFstab(&fstab)) {
            return Error() << "Could not read default fstab";
        }
    } else {
        if (!ReadFstabFromFile(*swapon_all, &fstab)) {
            return Error() << "Could not read fstab '" << *swapon_all << "'";
        }
    }

    if (!fs_mgr_swapon_all(fstab)) {                                                                                                           
        return Error() << "fs_mgr_swapon_all() failed";
    }

    return {};
}

而fs_mgr_swapon_all实现:/system/core/fs_mgr/fs_mgr.cpp:

bool fs_mgr_swapon_all(const Fstab& fstab) {
    ...
        const char* mkswap_argv[2] = {
                MKSWAP_BIN,
                entry.blk_device.c_str(),
        };
        int err = logwrap_fork_execvp(ARRAY_SIZE(mkswap_argv), mkswap_argv, nullptr, false,
                                      LOG_KLOG, false, nullptr);
        if (err) {
            LERROR << "mkswap failed for " << entry.blk_device;
            ret = false;
            continue;
        }

        /* If -1, then no priority was specified in fstab, so don't set
         * SWAP_FLAG_PREFER or encode the priority */
        int flags = 0;
        if (entry.swap_prio >= 0) {
            flags = (entry.swap_prio << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK;
            flags |= SWAP_FLAG_PREFER;
        } else {
            flags = 0;
        }
        err = swapon(entry.blk_device.c_str(), flags);
        if (err) {
            LERROR << "swapon failed for " << entry.blk_device;
            ret = false;
        }
        ...
}
2.swapon系统调用
kernel-5.15/mm/swapfile.c
swapon(...) {
    swap_file = file_open_name(name, O_RDWR|O_LARGEFILE, 0);
    p->swap_file = swap_file;
    mapping = swap_file->f_mapping;
    dentry = swap_file->f_path.dentry;
    inode = mapping->host;

     /*
     * Read the swap header.
     */
    if (!mapping->a_ops->readpage) {
        error = -EINVAL;
        goto bad_swap_unlock_inode;
    }
    page = read_mapping_page(mapping, 0, swap_file);
    if (IS_ERR(page)) {
        error = PTR_ERR(page);
        goto bad_swap_unlock_inode;
    }
    swap_header = kmap(page);

    maxpages = read_swap_header(p, swap_header, inode);

    ...

    nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map,                                                                          
        cluster_info, maxpages, &span);
    ...
    error = init_swap_address_space(p->type, maxpages);
    ...
}

 上面代码read_mapping_page是能够读取内容的关键是mapping对象,因为mapping->aops有readpage函数,但是这里mapping和mapping->aops是什么时候设置的?先公布答案:mapping的aops指向的是def_blk_aops,定义在kernel-5.15/block/fops.c:

const struct address_space_operations def_blk_aops = {                                                                                         
    .set_page_dirty = __set_page_dirty_buffers,
    .readpage   = blkdev_readpage,
    .readahead  = blkdev_readahead,
    .writepage  = blkdev_writepage,
    .write_begin    = blkdev_write_begin,
    .write_end  = blkdev_write_end,
    .writepages = blkdev_writepages,
    .direct_IO  = blkdev_direct_IO,
    .migratepage    = buffer_migrate_page_norefs,
    .is_dirty_writeback = buffer_check_dirty_writeback,
};

但是这是什么代码路径设置进去的呢?我们就以zram为例:一切要从blk_alloc_disk函数说起

zram_drv.c:
static int zram_add(void)
{
    struct zram *zram;
    int ret, device_id;

    zram = kzalloc(sizeof(struct zram), GFP_KERNEL);
    if (!zram)
        return -ENOMEM;

    ret = idr_alloc(&zram_index_idr, zram, 0, 0, GFP_KERNEL);
    if (ret < 0)
        goto out_free_dev;
    device_id = ret;

    init_rwsem(&zram->init_lock);
#ifdef CONFIG_ZRAM_WRITEBACK
    spin_lock_init(&zram->wb_limit_lock);
#endif

    /* gendisk structure */
    zram->disk = blk_alloc_disk(NUMA_NO_NODE);
    ...
}

__blk_alloc_disk(kernel-5.15/block/genhd.c)
    -->__alloc_disk_node(kernel-5.15/block/genhd.c)
        --->bdev_alloc(kernel-5.15/block/bdev.c)

struct block_device *bdev_alloc(struct gendisk *disk, u8 partno)
{
    struct block_device *bdev;
    struct inode *inode;

    inode = new_inode(blockdev_superblock);
    if (!inode)
        return NULL;
    inode->i_mode = S_IFBLK;
    inode->i_rdev = 0;
    inode->i_data.a_ops = &def_blk_aops;
    mapping_set_gfp_mask(&inode->i_data, GFP_USER);

    bdev = I_BDEV(inode);
    mutex_init(&bdev->bd_fsfreeze_mutex);
    spin_lock_init(&bdev->bd_size_lock);
    bdev->bd_partno = partno;
    bdev->bd_inode = inode;
    bdev->bd_stats = alloc_percpu(struct disk_stats);
    if (!bdev->bd_stats) {
        iput(inode);
        return NULL;
    }
    bdev->bd_disk = disk;
    return bdev;
}

看到bdev_alloc可以看到inode->i_data.a_ops = &def_blk_aops就是设置的地方了。同时这里还生成了block_device,我们再看下block_device是怎么生成的!!!这里的关键是上面的new_inode调用到了哪里?答案:kernel-5.15/fs/inode.c:new_inode函数:

kernel-5.15/fs/inode.c:

struct inode *new_inode(struct super_block *sb)                                                                                                
{
    struct inode *inode;

    spin_lock_prefetch(&sb->s_inode_list_lock);

    inode = new_inode_pseudo(sb);
    if (inode)
        inode_sb_list_add(inode);
    return inode;
}

kernel-5.15/fs/inode.c:

struct inode *new_inode_pseudo(struct super_block *sb)                                                                                         
{
    struct inode *inode = alloc_inode(sb);

    if (inode) {
        spin_lock(&inode->i_lock);
        inode->i_state = 0;
        spin_unlock(&inode->i_lock);
        INIT_LIST_HEAD(&inode->i_sb_list);
    }
    return inode;
}

kernel-5.15/fs/inode.c:

static struct inode *alloc_inode(struct super_block *sb)
{
    const struct super_operations *ops = sb->s_op;
    struct inode *inode;

    if (ops->alloc_inode)
        //调用对应的alloc_inode,我们分析的场景调用到了kernel-5.15/block/bdev.c:bdev_alloc_inode
        inode = ops->alloc_inode(sb);
    else
        inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);

    if (!inode)
        return NULL;

    //很重要的初始化函数:inode_init_always
    if (unlikely(inode_init_always(sb, inode))) {
        if (ops->destroy_inode) {
            ops->destroy_inode(inode);
            if (!ops->free_inode)
                return NULL;
        }
        inode->free_inode = ops->free_inode;
        i_callback(&inode->i_rcu);
        return NULL;
    }

    return inode;
}

最终new_inode调用到了kernel-5.15/fs/inode.c:z的alloc_inode函数如下:


static struct inode *bdev_alloc_inode(struct super_block *sb)                                                                                  
{
    struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL);

    if (!ei)
        return NULL;
    memset(&ei->bdev, 0, sizeof(ei->bdev));
    return &ei->vfs_inode;
}

int inode_init_always(struct super_block *sb, struct inode *inode)
{
    static const struct inode_operations empty_iops;
    static const struct file_operations no_open_fops = {.open = no_open};
    struct address_space *const mapping = &inode->i_data;

    inode->i_sb = sb;
    inode->i_blkbits = sb->s_blocksize_bits;
    inode->i_flags = 0;
    atomic64_set(&inode->i_sequence, 0);
    atomic_set(&inode->i_count, 1);
    inode->i_op = &empty_iops;
    inode->i_fop = &no_open_fops;
    inode->i_ino = 0;
    inode->__i_nlink = 1;
    inode->i_opflags = 0;
    if (sb->s_xattr)
        inode->i_opflags |= IOP_XATTR;
    i_uid_write(inode, 0);
    i_gid_write(inode, 0);
    atomic_set(&inode->i_writecount, 0);
    inode->i_size = 0;
    inode->i_write_hint = WRITE_LIFE_NOT_SET;
    inode->i_blocks = 0;
    inode->i_bytes = 0;
    inode->i_generation = 0;
    inode->i_pipe = NULL;
    inode->i_cdev = NULL;
    inode->i_link = NULL;
    inode->i_dir_seq = 0;
    inode->i_rdev = 0;
    inode->dirtied_when = 0;

    ...
    
    mapping->a_ops = &empty_aops;
    mapping->host = inode;
}

Linux 平台下zRAM 和 swap 使用(内存交换) 当内存不足时,linux 系统可以向ROM 要空间给内存使用,zram 和 swap 可以完成该功能。 zram: 是把物理内存的一部分划分出来,把不是常用的内存数据压缩后放到zram里, 用到的时候把数据解压出来, 相当于牺牲了一些cpu效率,变相增大了内存。 磁盘 swap:是把磁盘的一部分作为内存, 对应用来说完全是透明的,相当与增大了内存, 但是缺点很明显, 当用到swap的时候,速度会变... 阅读详情

相关推荐

Jetson内存瓶颈破解:reComputer载板Swap与ZRAM扩展实战

在嵌入式AI开发与边缘计算场景中,物理内存(RAM)不足是制约Jetson等设备运行大型AI模型(如YOLO系列)的常见瓶颈。Linux系统通过虚拟内存机制管理内存资源,其核心原理是利用存储空间扩展可用内存。Swap(交换空间)技术将低速存储(如SSD)虚拟为内存,而ZRAM则通过内存内压缩数据创造额外空间,两者结合能有效提升系统处理内存密集型任务的能力。其技术价值在于以较低成本突破硬件内存限制,保障AI推理、多进程应用等任务的稳定运行。本文聚焦于在搭载高速NVMe SSD的reComputer工业载板上,

weixin_30824479的博客 447

init.rc中语言使用

Android Init Language --------------------- The Android Init Language consists of four broad classes of statements, which are Actions, Commands, Services, and Options. All of these are line-oriented

kc58236582的博客 4520

创建swap交换内存,创建大文件,/etc/fstab 解析

dd if=/dev/zero of=/data/swap1 bs=1024 count=8192000 mkswap /app/swap1 swapon /app/swap1 swapon -s free -m vim /etc/fstab /data/swap1 swap swap defaults 0 0

tangbin0505的博客 1605

Android 8.0 系统启动流程之init.rc语法规则(六)

1、概述     init经过前两个阶段后,已经建立了属性系统和SELinux系统,但是init进程还需要执行很多其他的操作,还要启动许多关键的系统服务,但是如果都是像属性系统和SELinux系统那样一行行代码去做,显得有点杂乱繁琐,而且不容易扩展,所以Android系统引入了init.rc。     init.rc是init进程启动的配置脚本,这个脚本是用一种叫Android Init La...

marshal_zsx的博客 1万+

FortiClient EMS实战:从安装到配置的全流程优化指南

本文详细解析了FortiClient EMS 7.0版本的部署与优化全流程,帮助企业构建零信任终端安全体系。从环境规划、高效安装、终端纳管到高级运维,提供实战指南和优化技巧,特别适用于Windows Server环境,助力企业提升终端安全管理效率。

weixin_29325007的博客 547

MAPPO实战:从理论到代码的协作智能体训练指南

本文详细介绍了MAPPO算法在多智能体协作训练中的实战应用,从理论基础到代码实现全面解析。通过对比PPO与MAPPO的差异,深入讲解CTDE框架、网络架构设计、参数调优等关键环节,并提供实际项目中的调参经验和常见问题解决方案,帮助开发者快速掌握这一强化学习前沿技术。

weixin_42561040的博客 264

如何快速提升Linux系统性能:终极内存压缩优化指南

你是否曾因服务器内存不足而烦恼?是否体验过Swap分区导致的系统卡顿?今天,我们将深入探索Linux内核中的一项革命性技术——zram内存压缩,这项技术能让你在不增加硬件成本的情况下,显著提升系统性能。作为Linux内核的核心功能之一,zram通过智能内存压缩机制,将不活跃的内存页面压缩存储,从而释放宝贵的内存空间。 ## 问题场景:内存不足的痛点分析 想象一下这样的场景:你的服务器正在运行多

gitblog_00107的博客 307

松材线虫病害智能检测:基于YOLOv8的无人机航拍数据集构建与模型优化

本文探讨了基于YOLOv8的无人机航拍技术在松材线虫病害智能检测中的应用。通过构建高质量巡检数据集和优化模型架构(如RepVit主干网络和跨尺度特征融合模块),显著提升了病害识别准确率。该方案在复杂森林环境中表现出色,将检测效率提高数倍,为林业病害防控提供了高效解决方案。

vulkan6gpu的博客 994

小内存版本android,Android系统在小内存下的使用

最近在调试的方案,硬件配置是512MB的DDR,这在Android4.4这号称优化很大的系统版本上运行还是很吃力,找了一些资料,发现我们的方案上使用到了ZRAM这一技术,直接使用压缩内存来作为交换分区,其中涉及到的内核配置如下:CONFIG_SWAP=yCONFIG_CGROUP_MEM_RES_CTLR=yCONFIG_CGROUP_MEM_RES_CTLR_SWAP=yCONFIG_ZRAM=...

weixin_29377233的博客 334

玩转 Milvus(二):在 Ubuntu 22.04(WSL2)上安装 Milvus

本文详细介绍了在Ubuntu 22.04(WSL2)环境下安装Milvus向量数据库的两种单机模式:Milvus Lite和Milvus Standalone。Milvus Lite作为轻量级Python库,适合快速学习和小规模实验,只需通过pip安装即可使用。Milvus Standalone则支持Docker和Docker Compose两种部署方式,适合开发测试或小规模生产环境。文章对比了不同安装方式的优缺点,并提供了验证案例和常见问题解答,帮助开发者快速上手,实现简单的语义搜索功能。

企业级后端与 AI 应用开发双线探索 2507

加湿器方案-DLT8M04TS-杰力科创

基本组成: 一个触摸按键、一组RGB灯、一个雾化片、一个充电IC。 产品功能: 第一次上电光机状态,RGB红/绿/红灯依次闪烁灭; 2、按键功能:短按开关机和三档喷雾工作模式,第一次短按持续喷雾,短按第二次喷3S,停3S,短按第三次关闭喷雾模式,依次循环; 在喷雾或是不喷雾的状态下长按1.5S RGB灯渐变,一直循环,第二次长按当前灯光闪烁一下常亮,第三次长按关机; 3、持续喷雾定时5小时自动断电,间歇喷雾定时10小时自动断电,若在间歇工作时有切换为持续喷雾,那间歇喷雾的...

JLKCsz的博客 512

巧妇能为少米之炊(3)——压缩饼干(ZRAM)

这个是我认为小内存处理中比较靠谱的方式——zram。它就像压缩饼干一样,虽然小小一块饼干看起来不大(zram的压缩页面占用内存),但是一喝水,感觉立马饱了(释放一个页面的内容)。 1.简介 2.如何使能 3.工作流程 4.还有什么能做的? 简介: zram就是在发生swap事件的时候,不把要置换的页面置换到外部存储中,手机中的外部存储就是EMMC,电脑中的外部存

memoryjs的专栏 2万+

手把手教你用Python 3.11和Node.js 18在Windows 11上搭建Dify开发环境

本文提供了一份详尽的Windows 11本地Dify开发环境搭建指南。文章手把手教你完成从Python 3.11、Node.js 18的安装配置,到PostgreSQL、Redis数据库服务的部署,再到前后端服务的启动与联调的全过程,并包含常见问题排查与效能优化建议,旨在帮助开发者构建一个稳定、可调试的Dify本地开发环境。

fire9的博客 645

Android 源码 读懂 init.zygote32.rc 文件

Android Init 语言包含四类主要的语句,分别是动作、命令、服务和选项。 所有这些都是面向行的,由用空格分隔的标记组成。C 样式的反斜杠转义符可用于将空格插入标记。也可以使用双引号来防止空格将文本分成多个标记。反斜杠是一行中的最后一个字符时,可用于折行。 以#开头的行是注释。 Action 和 Service 隐式声明一个新的 Section。 所有命令(Command)或选项(Optio...

洪伟的专栏 1201

matlab 点云学习目录【2026最新版】

matlab 点云学习目录。博客长期更新,本文最近更新时间为:2026年6月15日。

点云侠的博客 3万+

基于YOLO系列的安全帽检测系统:从理论到实现的完整指南

安全帽检测作为计算机视觉在工业安全领域的重要应用,近年来得到了广泛关注。本文详细介绍了基于YOLOv5、YOLOv6、YOLOv7和YOLOv8的安全帽检测系统的完整实现方案,包括算法原理、数据集构建、模型训练、性能优化以及完整的UI界面设计。通过对比分析不同YOLO版本的性能差异,本文为工业安全检测系统的开发提供了全面的技术参考和实践指导。

YOLO 364

Linux基础命令---swapon

swapon在指定的设备上启用交换分区,使用的设备或文件由专用文件参数提供。它可以是”-Llabel”或”-UUUID”,以指示一个设备的标签或UUID。对swapon的调用通常发生在系统引导脚本中,使所有交换设备都可用,因此分页和交换活动交叉在多个设备和文件之间。此命令的适用范围:RedHat、RHEL、Ubuntu、Cen...

weixin_34226182的博客 549

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

zram disksize 设置

zram disksize 设置 小内存项目:1G,2G,3G RAM zram disksize设置. 高通: 高通的设置比较简单: 相关代码: init.qcom.post_boot.sh if [ -f /sys/block/zram0/disksize ]; then if [ -f /sys/block/zram0/use_dedup ]; then echo 1 > /sys/block/zram0/use_dedup fi if [ $MemTotal -le5242

wende32的博客 4977

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

android 临时关闭ZRAM

关闭ZRAM: sysctl -w vm.swappiness=0 swapoff /dev/block/zram0 查看容量 : cat /sys/block/zram0/disksize 查看使用swap的倾向0 -> 100 cat /proc/sys/vm/swappiness 设置zram 容量: find . -name fstab.enableswap 找到这个fstab.enableswap cat ./vendor/etc/fstab.enableswap /dev/bloc

zyfzhangyafei的专栏 6635

Android 低内存优化配置

zram的确可以优化内存不足的问题,但是心病还需心药医,内存不足最根本还是要从内存入手,增大内存才是治标治本之法。

lojotee的博客 5897

zram和swap

首先谈下EMMC上做个swap分区,经验:只会更差,速度会更差,试过这个方案后,睡眠唤醒后非常慢。 内存优化一般有几个方向: 1) 具体内存消耗比较大的应用,存在泄漏的应用 2) 内存裁剪、资源优化、显存裁剪(咨询高通) 3) AMS的trimapplication和kernel的lowmemorykiller的两个调度机制优化。 4) zram、swap zram是个以内存为

AKeywordSE的专栏 6996

zram原理及实践

ram(也称为 zRAM,先前称为 compcache)是 Linux 内核的一项功能,可提供虚拟内存压缩。zram 通过在 RAM 内的压缩块设备上分页,直到必须使用硬盘上的交换空间,以避免在磁盘上进行分页,从而提高性能。由于 zram 可以用内存替代硬盘为系统提供交换空间的功能,zram 可以在需要交换 / 分页时让 Linux 更好利用 RAM ,在物理内存较少的旧电脑上尤其如此。即使 RAM 的价格相对较低,zram 仍有利于嵌入式...

本人任职于安超云技术架构部,拥有十余年云计算与AI经验。专注AI基础设施、分布式集群、高可用架构、虚拟化、存储、网络及数据库等领域。博客内容以学习笔记为主,力求准确,但个人能力所限,难免疏误。非常欢迎交流指正,期待与您共同探讨技术 4828

【Android】一文总结Android的init语言

- 1、在Android系统中,存在多个以`xxx.rc`形式命名的文件,这些可以文件可以理解成Android系统配置文件,在Android系统启动过程中,由init进程加载并解析,这些文件中的内容形成了Android的init语言,是语言就存在一定的语法、格式、命令和参数等。 - 2、为了在阅读这些rc文件时不至于茫然无措,也为了更加深入的理解Android系统的启动过程,也为了后续能够深度的定制Android系统,总结了在rc文件中常使用的command、option等,便于备查理解!

iriczhao的博客 2203

【性能优化】启用zram

摘要:ZRAM是一种内存压缩技术,可在系统内存不足时启用。启用方法包括:1)检查内核版本(需3.14+);2)初始化/dev/zram0并设置为swap分区;3)调整swappiness参数(100表示优先使用swap)。启用后可能增加CPU负载,需根据内存总量、内核支持等情况权衡使用。最后可通过/proc/swaps查看swap配置状态。

林多 1265

Android源码分析 - init进程

本篇以android-11.0.0_r25作为基础解析PC启动会通过BIOS引导,从0x7c00处找到以0xaa55为结尾的引导程序启动。而Android通常使用在移动设备上,没有PC的BIOS,取而代之的是BootLoader。在CPU上电复位完成后,会从一个固定的地址加载一段程序,即BootLoader,不同的CPU可能这个地址不同。BootLoader是一段引导程序,其中最为常见的为U-boot,它一般会先检测用户是否按下某些特别按键,这些特别按键是uboot在编译时预先被约定好的,用于进入调试模式。

qq_34231329的博客 1235

Android Init Language

Android Init语言包含五种主要的语句类:Actions, Commands, Services, Options, and Imports. 所有这些都是面向行的,由用空格分隔的标记组成。C样式的反斜杠转义符可用于将空格插入token。也可以使用双引号来防止空格将文本分成多个标记。反斜杠是一行中的最后一个字符时,可用于折行。 以#开头的行(允许前导空格)是注释。 可以使用语法$ {property.name}扩展系统属性。这也适用于需要连接的上下文,例如import /init.recov.

hi_zhengjian的专栏 1576
上一篇: Linux pi futex锁优先级继承实现原理
下一篇: Linux Swap机制关键点分析
OS技术解密
博客等级 码龄16年 3760粉丝 189原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值