swapon-off系统调用及示例

swapon/swapoff 函数详解

1. 函数介绍

swapon 和 swapoff 是Linux系统调用,用于管理系统的交换空间(swap space)。交换空间是磁盘上的一块区域,当物理内存不足时,系统会将不常用的内存页移动到交换空间,从而释放物理内存供其他进程使用。

2. 函数原型

#include <sys/swap.h>

int swapon(const char *path, int swapflags);
int swapoff(const char *path);

3. 功能

  • swapon: 启用指定的交换空间(文件或设备)
  • swapoff: 禁用指定的交换空间

4. 参数

  • *const char path: 交换文件或设备的路径
  • int swapflags: swapon的标志位(通常为0)

5. 返回值

  • 成功: 返回0
  • 失败: 返回-1,并设置errno

6. 相似函数,或关联函数

  • swapctl: 更通用的交换控制接口
  • mkswap: 创建交换空间
  • /proc/swaps: 交换空间信息文件
  • free: 显示内存使用情况

7. 示例代码

示例1:基础swapon/swapoff使用

#include <sys/swap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

/**
 * 显示当前交换空间信息
 */
void show_swap_info() {
    FILE *fp;
    char line[256];
    
    printf("=== 当前交换空间信息 ===\n");
    
    fp = fopen("/proc/swaps", "r");
    if (fp) {
        printf("交换空间列表:\n");
        while (fgets(line, sizeof(line), fp)) {
            printf("  %s", line);
        }
        fclose(fp);
    } else {
        printf("无法读取交换空间信息: %s\n", strerror(errno));
    }
    
    printf("\n内存使用情况:\n");
    system("free -h");
    printf("\n");
}

/**
 * 创建交换文件
 */
int create_swap_file(const char *filename, size_t size_mb) {
    int fd;
    char *buffer;
    size_t chunk_size = 1024 * 1024;  // 1MB chunks
    size_t written = 0;
    
    printf("创建交换文件: %s (%zu MB)\n", filename, size_mb);
    
    // 创建文件
    fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
    if (fd == -1) {
        perror("创建交换文件失败");
        return -1;
    }
    
    // 设置文件大小
    if (ftruncate(fd, size_mb * 1024 * 1024) == -1) {
        perror("设置文件大小失败");
        close(fd);
        unlink(filename);
        return -1;
    }
    
    // 可选:填充文件内容(对于某些文件系统可能需要)
    buffer = malloc(chunk_size);
    if (buffer) {
        memset(buffer, 0, chunk_size);
        
        // 写入一些数据以确保文件分配
        ssize_t result = write(fd, buffer, chunk_size);
        if (result == -1) {
            perror("写入文件失败");
        }
        
        free(buffer);
    }
    
    close(fd);
    
    // 创建交换空间
    printf("初始化交换空间...\n");
    char cmd[256];
    snprintf(cmd, sizeof(cmd), "mkswap %s", filename);
    
    int result = system(cmd);
    if (result != 0) {
        printf("创建交换空间失败\n");
        unlink(filename);
        return -1;
    }
    
    printf("交换文件创建成功\n");
    return 0;
}

/**
 * 演示基础swapon/swapoff使用方法
 */
int demo_swapon_swapoff_basic() {
    const char *swap_file = "/tmp/test_swapfile";
    const size_t swap_size = 64;  // 64MB
    int result;
    
    printf("=== 基础swapon/swapoff使用示例 ===\n");
    
    // 检查权限
    uid_t uid = getuid();
    printf("用户权限检查:\n");
    printf("  当前用户ID: %d\n", uid);
    if (uid == 0) {
        printf("  ✓ 具有root权限,可以管理交换空间\n");
    } else {
        printf("  ✗ 没有root权限,交换空间管理将失败\n");
        printf("  注意:swapon/swapoff需要root权限\n");
        return 0;
    }
    
    // 显示原始交换空间信息
    printf("\n1. 原始交换空间信息:\n");
    show_swap_info();
    
    // 创建交换文件
    printf("2. 创建测试交换文件:\n");
    if (create_swap_file(swap_file, swap_size) != 0) {
        printf("创建交换文件失败\n");
        return -1;
    }
    
    // 启用交换文件
    printf("3. 启用交换文件:\n");
    printf("   交换文件路径: %s\n", swap_file);
    
    result = swapon(swap_file, 0);
    if (result == 0) {
        printf("   ✓ 交换文件启用成功\n");
        show_swap_info();
    } else {
        printf("   ✗ 交换文件启用失败: %s\n", strerror(errno));
        if (errno == EPERM) {
            printf("   原因:权限不足\n");
        } else if (errno == EBUSY) {
            printf("   原因:交换空间已在使用中\n");
        } else if (errno == EINVAL) {
            printf("   原因:无效的交换文件\n");
        }
        unlink(swap_file);
        return -1;
    }
    
    // 禁用交换文件
    printf("4. 禁用交换文件:\n");
    result = swapoff(swap_file);
    if (result == 0) {
        printf("   ✓ 交换文件禁用成功\n");
        show_swap_info();
    } else {
        printf("   ✗ 交换文件禁用失败: %s\n", strerror(errno));
        if (errno == EPERM) {
            printf("   原因:权限不足\n");
        } else if (errno == EINVAL) {
            printf("   原因:无效的交换文件路径\n");
        } else if (errno == EBUSY) {
            printf("   原因:交换空间忙或正在使用\n");
        }
    }
    
    // 清理测试文件
    printf("5. 清理测试文件:\n");
    if (unlink(swap_file) == 0) {
        printf("   ✓ 测试文件清理成功\n");
    } else {
        printf("   ✗ 测试文件清理失败: %s\n", strerror(errno));
    }
    
    return 0;
}

int main() {
    return demo_swapon_swapoff_basic();
}

示例2:交换空间管理工具

#include <sys/swap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <getopt.h>

/**
 * 交换空间条目结构
 */
typedef struct {
    char path[256];
    long size_kb;
    long used_kb;
    int priority;
    char type[32];
} swap_entry_t;

/**
 * 解析交换空间信息
 */
int parse_swap_info(swap_entry_t *entries, int max_entries) {
    FILE *fp;
    char line[512];
    int count = 0;
    
    fp = fopen("/proc/swaps", "r");
    if (!fp) {
        return -1;
    }
    
    // 跳过标题行
    fgets(line, sizeof(line), fp);
    
    while (fgets(line, sizeof(line), fp) && count < max_entries) {
        char *token;
        char *saveptr;
        int field = 0;
        
        token = strtok_r(line, " \t\n", &saveptr);
        while (token && field < 5) {
            switch (field) {
                case 0:  // Filename
                    strncpy(entries[count].path, token, sizeof(entries[count].path) - 1);
                    entries[count].path[sizeof(entries[count].path) - 1] = '\0';
                    break;
                case 1:  // Type
                    strncpy(entries[count].type, token, sizeof(entries[count].type) - 1);
                    entries[count].type[sizeof(entries[count].type) - 1] = '\0';
                    break;
                case 2:  // Size
                    entries[count].size_kb = atol(token);
                    break;
                case 3:  // Used
                    entries[count].used_kb = atol(token);
                    break;
                case 4:  // Priority
                    entries[count].priority = atoi(token);
                    break;
            }
            token = strtok_r(NULL, " \t\n", &saveptr);
            field++;
        }
        
        if (field >= 4) {
            count++;
        }
    }
    
    fclose(fp);
    return count;
}

/**
 * 显示详细的交换空间信息
 */
void show_detailed_swap_info() {
    swap_entry_t entries[32];
    int count = parse_swap_info(entries, 32);
    
    printf("=== 详细交换空间信息 ===\n");
    
    if (count <= 0) {
        printf("没有活动的交换空间\n");
        return;
    }
    
    printf("%-20s %-10s %-12s %-12s %-10s %-8s\n",
           "路径", "类型", "大小(MB)", "已用(MB)", "可用(MB)", "优先级");
    printf("%-20s %-10s %-12s %-12s %-10s %-8s\n",
           "----", "----", "--------", "--------", "--------", "------");
    
    long total_size = 0, total_used = 0;
    
    for (int i = 0; i < count; i++) {
        double size_mb = entries[i].size_kb / 1024.0;
        double used_mb = entries[i].used_kb / 1024.0;
        double free_mb = (entries[i].size_kb - entries[i].used_kb) / 1024.0;
        
        printf("%-20s %-10s %-12.1f %-12.1f %-10.1f %-8d\n",
               entries[i].path,
               entries[i].type,
               size_mb,
               used_mb,
               free_mb,
               entries[i].priority);
        
        total_size += entries[i].size_kb;
        total_used += entries[i].used_kb;
    }
    
    printf("\n总计:\n");
    printf("  总大小: %.1f MB\n", total_size / 1024.0);
    printf("  已使用: %.1f MB\n", total_used / 1024.0);
    printf("  可用: %.1f MB\n", (total_size - total_used) / 1024.0);
    printf("  使用率: %.1f%%\n", 
           total_size > 0 ? (total_used * 100.0 / total_size) : 0.0);
}

/**
 * 交换空间管理工具
 */
int demo_swap_management_tool() {
    const char *test_swap_file = "/tmp/swap_management_test";
    uid_t uid = getuid();
    
    printf("=== 交换空间管理工具演示 ===\n");
    
    // 权限检查
    printf("权限检查:\n");
    printf("  当前用户ID: %d\n", uid);
    if (uid == 0) {
        printf("  ✓ 具有root权限\n");
    } else {
        printf("  ✗ 没有root权限,部分功能将受限\n");
    }
    
    // 显示当前交换空间状态
    printf("\n1. 当前交换空间状态:\n");
    show_detailed_swap_info();
    
    // 如果有root权限,演示创建和管理交换文件
    if (uid == 0) {
        printf("\n2. 创建测试交换文件:\n");
        
        // 创建小的交换文件用于测试
        int fd = open(test_swap_file, O_CREAT | O_WRONLY | O_TRUNC, 0600);
        if (fd != -1) {
            // 设置文件大小为32MB
            if (ftruncate(fd, 32 * 1024 * 1024) == 0) {
                close(fd);
                
                // 创建交换空间
                char cmd[256];
                snprintf(cmd, sizeof(cmd), "mkswap %s >/dev/null 2>&1", test_swap_file);
                if (system(cmd) == 0) {
                    printf("  ✓ 创建交换文件成功: %s\n", test_swap_file);
                    
                    // 启用交换文件
                    printf("3. 启用交换文件:\n");
                    int result = swapon(test_swap_file, 0);
                    if (result == 0) {
                        printf("  ✓ 交换文件启用成功\n");
                        show_detailed_swap_info();
                        
                        // 禁用交换文件
                        printf("\n4. 禁用交换文件:\n");
                        result = swapoff(test_swap_file);
                        if (result == 0) {
                            printf("  ✓ 交换文件禁用成功\n");
                        } else {
                            printf("  ✗ 交换文件禁用失败: %s\n", strerror(errno));
                        }
                    } else {
                        printf("  ✗ 交换文件启用失败: %s\n", strerror(errno));
                    }
                } else {
                    printf("  ✗ 初始化交换空间失败\n");
                }
            } else {
                perror("  设置文件大小失败");
                close(fd);
            }
            
            // 清理测试文件
            unlink(test_swap_file);
        } else {
            perror("  创建交换文件失败");
        }
    }
    
    // 显示交换空间管理建议
    printf("\n=== 交换空间管理建议 ===\n");
    printf("1. 交换空间大小:\n");
    printf("   - 物理内存 < 2GB: 交换空间 = 物理内存 × 2\n");
    printf("   - 物理内存 2-8GB: 交换空间 = 物理内存\n");
    printf("   - 物理内存 > 8GB: 交换空间 = 4-8GB\n");
    
    printf("\n2. 交换空间类型:\n");
    printf("   - 交换分区: 性能更好,推荐用于生产环境\n");
    printf("   - 交换文件: 灵活性更好,便于管理\n");
    
    printf("\n3. 优先级设置:\n");
    printf("   - 高速设备设置高优先级\n");
    printf("   - SSD交换空间优先级高于HDD\n");
    
    printf("\n4. 监控和维护:\n");
    printf("   - 定期检查交换空间使用情况\n");
    printf("   - 避免交换空间使用率过高\n");
    printf("   - 及时清理不需要的交换文件\n");
    
    return 0;
}

int main() {
    return demo_swap_management_tool();
}

示例3:动态交换空间管理

#include <sys/swap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

/**
 * 交换空间监控器
 */
typedef struct {
    long total_swap_kb;
    long used_swap_kb;
    double usage_percentage;
    time_t last_update;
} swap_monitor_t;

/**
 * 获取交换空间使用情况
 */
int get_swap_usage(swap_monitor_t *monitor) {
    FILE *fp;
    char line[256];
    
    fp = fopen("/proc/meminfo", "r");
    if (!fp) {
        return -1;
    }
    
    long swap_total = 0, swap_free = 0;
    
    while (fgets(line, sizeof(line), fp)) {
        if (strncmp(line, "SwapTotal:", 10) == 0) {
            sscanf(line + 10, "%ld", &swap_total);
        } else if (strncmp(line, "SwapFree:", 9) == 0) {
            sscanf(line + 9, "%ld", &swap_free);
        }
    }
    
    fclose(fp);
    
    monitor->total_swap_kb = swap_total;
    monitor->used_swap_kb = swap_total - swap_free;
    monitor->usage_percentage = swap_total > 0 ? 
        (monitor->used_swap_kb * 100.0 / swap_total) : 0.0;
    monitor->last_update = time(NULL);
    
    return 0;
}

/**
 * 显示交换空间使用情况
 */
void show_swap_usage(const swap_monitor_t *monitor) {
    printf("交换空间使用情况:\n");
    printf("  总大小: %.1f MB\n", monitor->total_swap_kb / 1024.0);
    printf("  已使用: %.1f MB\n", monitor->used_swap_kb / 1024.0);
    printf("  可用: %.1f MB\n", (monitor->total_swap_kb - monitor->used_swap_kb) / 1024.0);
    printf("  使用率: %.1f%%\n", monitor->usage_percentage);
    
    char time_str[64];
    strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", 
             localtime(&monitor->last_update));
    printf("  更新时间: %s\n", time_str);
}

/**
 * 动态交换空间管理器
 */
typedef struct {
    char swap_file[256];
    size_t initial_size_mb;
    size_t max_size_mb;
    int is_active;
    swap_monitor_t monitor;
} dynamic_swap_manager_t;

/**
 * 创建动态交换文件
 */
int create_dynamic_swap_file(dynamic_swap_manager_t *manager, size_t size_mb) {
    int fd;
    
    printf("创建动态交换文件: %s (%zu MB)\n", manager->swap_file, size_mb);
    
    // 创建文件
    fd = open(manager->swap_file, O_CREAT | O_WRONLY | O_TRUNC, 0600);
    if (fd == -1) {
        perror("创建交换文件失败");
        return -1;
    }
    
    // 设置文件大小
    if (ftruncate(fd, size_mb * 1024 * 1024) == -1) {
        perror("设置文件大小失败");
        close(fd);
        unlink(manager->swap_file);
        return -1;
    }
    
    close(fd);
    
    // 创建交换空间
    char cmd[512];
    snprintf(cmd, sizeof(cmd), "mkswap %s >/dev/null 2>&1", manager->swap_file);
    
    if (system(cmd) != 0) {
        printf("初始化交换空间失败\n");
        unlink(manager->swap_file);
        return -1;
    }
    
    printf("动态交换文件创建成功\n");
    return 0;
}

/**
 * 启用动态交换空间
 */
int activate_dynamic_swap(dynamic_swap_manager_t *manager) {
    if (manager->is_active) {
        printf("交换空间已在使用中\n");
        return 0;
    }
    
    printf("启用动态交换空间...\n");
    
    int result = swapon(manager->swap_file, 0);
    if (result == 0) {
        manager->is_active = 1;
        printf("✓ 动态交换空间启用成功\n");
        return 0;
    } else {
        printf("✗ 动态交换空间启用失败: %s\n", strerror(errno));
        return -1;
    }
}

/**
 * 禁用动态交换空间
 */
int deactivate_dynamic_swap(dynamic_swap_manager_t *manager) {
    if (!manager->is_active) {
        printf("交换空间未启用\n");
        return 0;
    }
    
    printf("禁用动态交换空间...\n");
    
    int result = swapoff(manager->swap_file);
    if (result == 0) {
        manager->is_active = 0;
        printf("✓ 动态交换空间禁用成功\n");
        return 0;
    } else {
        printf("✗ 动态交换空间禁用失败: %s\n", strerror(errno));
        return -1;
    }
}

/**
 * 演示动态交换空间管理
 */
int demo_dynamic_swap_management() {
    dynamic_swap_manager_t manager = {0};
    uid_t uid = getuid();
    
    printf("=== 动态交换空间管理演示 ===\n");
    
    // 权限检查
    if (uid != 0) {
        printf("需要root权限来管理交换空间\n");
        return 0;
    }
    
    // 初始化管理器
    strncpy(manager.swap_file, "/tmp/dynamic_swap", sizeof(manager.swap_file) - 1);
    manager.initial_size_mb = 64;
    manager.max_size_mb = 256;
    manager.is_active = 0;
    
    printf("动态交换管理器初始化:\n");
    printf("  交换文件: %s\n", manager.swap_file);
    printf("  初始大小: %zu MB\n", manager.initial_size_mb);
    printf("  最大大小: %zu MB\n", manager.max_size_mb);
    
    // 获取初始交换空间状态
    printf("\n1. 初始交换空间状态:\n");
    if (get_swap_usage(&manager.monitor) == 0) {
        show_swap_usage(&manager.monitor);
    }
    
    // 创建并启用动态交换空间
    printf("\n2. 创建动态交换空间:\n");
    if (create_dynamic_swap_file(&manager, manager.initial_size_mb) != 0) {
        printf("创建动态交换空间失败\n");
        return -1;
    }
    
    printf("\n3. 启用动态交换空间:\n");
    if (activate_dynamic_swap(&manager) != 0) {
        printf("启用动态交换空间失败\n");
        unlink(manager.swap_file);
        return -1;
    }
    
    // 显示启用后的状态
    printf("\n4. 启用后的交换空间状态:\n");
    sleep(1);  // 等待系统更新状态
    if (get_swap_usage(&manager.monitor) == 0) {
        show_swap_usage(&manager.monitor);
    }
    
    // 模拟监控和调整
    printf("\n5. 监控交换空间使用情况:\n");
    for (int i = 0; i < 3; i++) {
        sleep(2);
        if (get_swap_usage(&manager.monitor) == 0) {
            printf("监控轮次 %d:\n", i + 1);
            show_swap_usage(&manager.monitor);
            
            // 简单的使用率监控逻辑
            if (manager.monitor.usage_percentage > 80.0) {
                printf("  警告:交换空间使用率过高 (%.1f%%)\n", 
                       manager.monitor.usage_percentage);
            } else if (manager.monitor.usage_percentage > 50.0) {
                printf("  提示:交换空间使用率中等 (%.1f%%)\n", 
                       manager.monitor.usage_percentage);
            } else {
                printf("  状态:交换空间使用率正常 (%.1f%%)\n", 
                       manager.monitor.usage_percentage);
            }
        }
    }
    
    // 禁用并清理
    printf("\n6. 禁用动态交换空间:\n");
    if (deactivate_dynamic_swap(&manager) != 0) {
        printf("禁用动态交换空间失败\n");
    }
    
    // 显示最终状态
    printf("\n7. 最终交换空间状态:\n");
    sleep(1);  // 等待系统更新状态
    if (get_swap_usage(&manager.monitor) == 0) {
        show_swap_usage(&manager.monitor);
    }
    
    // 清理文件
    printf("\n8. 清理交换文件:\n");
    if (unlink(manager.swap_file) == 0) {
        printf("✓ 交换文件清理成功\n");
    } else {
        printf("✗ 交换文件清理失败: %s\n", strerror(errno));
    }
    
    // 显示管理策略建议
    printf("\n=== 动态交换空间管理策略 ===\n");
    printf("1. 自动扩展策略:\n");
    printf("   - 监控交换空间使用率\n");
    printf("   - 使用率 > 80% 时扩展\n");
    printf("   - 使用率 < 30% 时收缩\n");
    
    printf("\n2. 性能优化:\n");
    printf("   - 使用SSD作为交换空间\n");
    printf("   - 设置适当的优先级\n");
    printf("   - 避免频繁的启用/禁用操作\n");
    
    printf("\n3. 安全考虑:\n");
    printf("   - 交换文件权限设置为600\n");
    printf("   - 定期清理临时交换文件\n");
    printf("   - 监控异常的交换空间使用\n");
    
    return 0;
}

int main() {
    return demo_dynamic_swap_management();
}

示例4:交换空间优先级管理

#include <sys/swap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

/**
 * 交换优先级管理器
 */
typedef struct {
    char path[256];
    int priority;
    int is_active;
} priority_swap_t;

/**
 * 创建带优先级的交换文件
 */
int create_priority_swap_file(const char *filename, size_t size_mb, int priority) {
    int fd;
    
    printf("创建优先级交换文件: %s (大小: %zu MB, 优先级: %d)\n", 
           filename, size_mb, priority);
    
    // 创建文件
    fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
    if (fd == -1) {
        perror("创建交换文件失败");
        return -1;
    }
    
    // 设置文件大小
    if (ftruncate(fd, size_mb * 1024 * 1024) == -1) {
        perror("设置文件大小失败");
        close(fd);
        unlink(filename);
        return -1;
    }
    
    close(fd);
    
    // 创建交换空间
    char cmd[512];
    snprintf(cmd, sizeof(cmd), "mkswap %s >/dev/null 2>&1", filename);
    
    if (system(cmd) != 0) {
        printf("初始化交换空间失败\n");
        unlink(filename);
        return -1;
    }
    
    printf("交换文件创建成功\n");
    return 0;
}

/**
 * 启用带优先级的交换空间
 */
int activate_priority_swap(const char *filename, int priority) {
    printf("启用优先级交换空间: %s (优先级: %d)\n", filename, priority);
    
    // 使用swapflags设置优先级
    int swapflags = (priority << 16);  // 优先级存储在高16位
    
    int result = swapon(filename, swapflags);
    if (result == 0) {
        printf("✓ 交换空间启用成功\n");
        return 0;
    } else {
        printf("✗ 交换空间启用失败: %s\n", strerror(errno));
        return -1;
    }
}

/**
 * 演示交换空间优先级管理
 */
int demo_swap_priority_management() {
    priority_swap_t swaps[3];
    uid_t uid = getuid();
    
    printf("=== 交换空间优先级管理演示 ===\n");
    
    // 权限检查
    if (uid != 0) {
        printf("需要root权限来管理交换空间\n");
        return 0;
    }
    
    // 初始化交换空间配置
    strncpy(swaps[0].path, "/tmp/priority_swap_high", sizeof(swaps[0].path) - 1);
    swaps[0].priority = 10;  // 高优先级
    swaps[0].is_active = 0;
    
    strncpy(swaps[1].path, "/tmp/priority_swap_medium", sizeof(swaps[1].path) - 1);
    swaps[1].priority = 5;   // 中优先级
    swaps[1].is_active = 0;
    
    strncpy(swaps[2].path, "/tmp/priority_swap_low", sizeof(swaps[2].path) - 1);
    swaps[2].priority = 1;   // 低优先级
    swaps[2].is_active = 0;
    
    printf("交换空间优先级配置:\n");
    for (int i = 0; i < 3; i++) {
        printf("  %s: 优先级 %d\n", swaps[i].path, swaps[i].priority);
    }
    
    // 显示初始交换空间状态
    printf("\n1. 初始交换空间状态:\n");
    system("cat /proc/swaps");
    
    // 创建交换文件
    printf("\n2. 创建交换文件:\n");
    for (int i = 0; i < 3; i++) {
        size_t size_mb = 32 + i * 16;  // 32MB, 48MB, 64MB
        if (create_priority_swap_file(swaps[i].path, size_mb, swaps[i].priority) != 0) {
            printf("创建交换文件 %s 失败\n", swaps[i].path);
            // 清理已创建的文件
            for (int j = 0; j < i; j++) {
                unlink(swaps[j].path);
            }
            return -1;
        }
    }
    
    // 按优先级顺序启用交换空间
    printf("\n3. 按优先级启用交换空间:\n");
    // 注意:实际的优先级设置可能需要通过命令行参数传递
    for (int i = 0; i < 3; i++) {
        printf("启用交换空间 %d:\n", i + 1);
        // 这里简化处理,实际应用中可能需要更复杂的优先级设置
        int result = swapon(swaps[i].path, 0);
        if (result == 0) {
            swaps[i].is_active = 1;
            printf("  ✓ %s 启用成功\n", swaps[i].path);
        } else {
            printf("  ✗ %s 启用失败: %s\n", swaps[i].path, strerror(errno));
        }
    }
    
    // 显示启用后的状态
    printf("\n4. 启用后的交换空间状态:\n");
    system("cat /proc/swaps");
    
    printf("\n交换空间优先级说明:\n");
    printf("  - 数值越高优先级越高\n");
    printf("  - 高优先级交换空间先被使用\n");
    printf("  - 相同优先级的交换空间轮询使用\n");
    
    // 禁用交换空间
    printf("\n5. 禁用交换空间:\n");
    for (int i = 0; i < 3; i++) {
        if (swaps[i].is_active) {
            int result = swapoff(swaps[i].path);
            if (result == 0) {
                swaps[i].is_active = 0;
                printf("  ✓ %s 禁用成功\n", swaps[i].path);
            } else {
                printf("  ✗ %s 禁用失败: %s\n", swaps[i].path, strerror(errno));
            }
        }
    }
    
    // 清理文件
    printf("\n6. 清理交换文件:\n");
    for (int i = 0; i < 3; i++) {
        if (unlink(swaps[i].path) == 0) {
            printf("  ✓ %s 清理成功\n", swaps[i].path);
        } else {
            printf("  ✗ %s 清理失败: %s\n", swaps[i].path, strerror(errno));
        }
    }
    
    // 显示优先级管理最佳实践
    printf("\n=== 交换空间优先级管理最佳实践 ===\n");
    printf("1. 优先级设置原则:\n");
    printf("   - SSD交换空间设置高优先级\n");
    printf("   - 高速磁盘设置中等优先级\n");
    printf("   - 低速磁盘设置低优先级\n");
    
    printf("\n2. 负载均衡:\n");
    printf("   - 相同类型设备设置相同优先级\n");
    printf("   - 实现轮询使用,延长设备寿命\n");
    
    printf("\n3. 性能优化:\n");
    printf("   - 避免频繁调整优先级\n");
    printf("   - 根据实际性能测试设置\n");
    printf("   - 考虑I/O模式和访问模式\n");
    
    return 0;
}

int main() {
    return demo_swap_priority_management();
}

示例5:交换空间性能测试

#include <sys/swap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <sys/resource.h>

/**
 * 内存压力测试器
 */
typedef struct {
    size_t allocated_memory_mb;
    size_t swap_used_mb;
    double test_duration_seconds;
    int swap_enabled;
} memory_test_result_t;

/**
 * 分配内存并测试交换性能
 */
int memory_pressure_test(size_t memory_mb, memory_test_result_t *result) {
    char **buffers;
    size_t num_buffers = memory_mb / 10;  // 每个缓冲区10MB
    size_t buffer_size = 10 * 1024 * 1024;  // 10MB
    struct timespec start, end;
    
    printf("开始内存压力测试: %zu MB\n", memory_mb);
    
    // 记录开始时间
    clock_gettime(CLOCK_MONOTONIC, &start);
    
    // 分配内存缓冲区数组
    buffers = malloc(num_buffers * sizeof(char*));
    if (!buffers) {
        printf("分配缓冲区数组失败\n");
        return -1;
    }
    
    // 逐步分配内存
    size_t allocated_buffers = 0;
    for (size_t i = 0; i < num_buffers; i++) {
        buffers[i] = malloc(buffer_size);
        if (buffers[i]) {
            // 填充数据以确保内存实际使用
            memset(buffers[i], i & 0xFF, buffer_size);
            allocated_buffers++;
            
            if (allocated_buffers % 10 == 0) {
                printf("已分配 %zu MB 内存\n", allocated_buffers * 10);
            }
        } else {
            printf("内存分配失败在第 %zu 次\n", i + 1);
            break;
        }
    }
    
    // 记录结束时间
    clock_gettime(CLOCK_MONOTONIC, &end);
    
    result->allocated_memory_mb = allocated_buffers * 10;
    result->test_duration_seconds = (end.tv_sec - start.tv_sec) + 
                                   (end.tv_nsec - start.tv_nsec) / 1e9;
    
    printf("内存分配完成: %zu MB, 耗时 %.2f 秒\n", 
           result->allocated_memory_mb, result->test_duration_seconds);
    
    // 检查交换空间使用情况
    FILE *fp = fopen("/proc/meminfo", "r");
    if (fp) {
        char line[256];
        long swap_total = 0, swap_free = 0;
        
        while (fgets(line, sizeof(line), fp)) {
            if (strncmp(line, "SwapTotal:", 10) == 0) {
                sscanf(line + 10, "%ld", &swap_total);
            } else if (strncmp(line, "SwapFree:", 9) == 0) {
                sscanf(line + 9, "%ld", &swap_free);
            }
        }
        
        fclose(fp);
        result->swap_used_mb = (swap_total - swap_free) / 1024;  // 转换为MB
        result->swap_enabled = (swap_total > 0);
    }
    
    // 释放内存
    for (size_t i = 0; i < allocated_buffers; i++) {
        if (buffers[i]) {
            free(buffers[i]);
        }
    }
    free(buffers);
    
    return 0;
}

/**
 * 演示交换空间性能测试
 */
int demo_swap_performance_test() {
    const char *test_swap_file = "/tmp/performance_test_swap";
    uid_t uid = getuid();
    
    printf("=== 交换空间性能测试演示 ===\n");
    
    // 权限检查
    if (uid != 0) {
        printf("需要root权限来管理交换空间\n");
        printf("将以普通用户权限进行内存测试\n");
    }
    
    // 显示系统内存信息
    printf("1. 系统内存信息:\n");
    system("free -h");
    
    printf("\n2. 当前交换空间信息:\n");
    system("cat /proc/swaps");
    
    // 如果有root权限,创建测试交换空间
    if (uid == 0) {
        printf("\n3. 创建测试交换空间:\n");
        
        // 创建128MB交换文件
        int fd = open(test_swap_file, O_CREAT | O_WRONLY | O_TRUNC, 0600);
        if (fd != -1) {
            if (ftruncate(fd, 128 * 1024 * 1024) == 0) {
                close(fd);
                
                // 创建交换空间
                char cmd[256];
                snprintf(cmd, sizeof(cmd), "mkswap %s >/dev/null 2>&1", test_swap_file);
                if (system(cmd) == 0) {
                    printf("  ✓ 创建测试交换文件成功\n");
                    
                    // 启用交换文件
                    if (swapon(test_swap_file, 0) == 0) {
                        printf("  ✓ 启用测试交换文件成功\n");
                        system("cat /proc/swaps");
                    } else {
                        printf("  ✗ 启用测试交换文件失败\n");
                    }
                } else {
                    printf("  ✗ 初始化交换空间失败\n");
                    close(fd);
                    unlink(test_swap_file);
                }
            } else {
                perror("  设置文件大小失败");
                close(fd);
                unlink(test_swap_file);
            }
        } else {
            perror("  创建交换文件失败");
        }
    }
    
    // 进行内存压力测试
    printf("\n4. 内存压力测试:\n");
    
    // 测试不同内存大小
    size_t test_sizes[] = {100, 200, 300, 400};
    int num_tests = sizeof(test_sizes) / sizeof(test_sizes[0]);
    
    for (int i = 0; i < num_tests; i++) {
        printf("\n测试 %d: 分配 %zu MB 内存\n", i + 1, test_sizes[i]);
        
        memory_test_result_t result = {0};
        if (memory_pressure_test(test_sizes[i], &result) == 0) {
            printf("  测试结果:\n");
            printf("    分配内存: %zu MB\n", result.allocated_memory_mb);
            printf("    测试耗时: %.2f 秒\n", result.test_duration_seconds);
            printf("    交换使用: %zu MB\n", result.swap_used_mb);
            printf("    交换启用: %s\n", result.swap_enabled ? "是" : "否");
            
            if (result.swap_enabled && result.swap_used_mb > 0) {
                printf("    ✓ 交换空间正常工作\n");
            } else if (result.swap_enabled) {
                printf("    提示:交换空间已启用但未使用\n");
            } else {
                printf("    提示:交换空间未启用\n");
            }
        } else {
            printf("  测试失败\n");
        }
        
        // 短暂休息
        sleep(2);
    }
    
    // 如果创建了测试交换空间,清理它
    if (uid == 0) {
        printf("\n5. 清理测试交换空间:\n");
        
        // 禁用交换文件
        if (swapoff(test_swap_file) == 0) {
            printf("  ✓ 禁用测试交换文件成功\n");
        } else {
            printf("  ✗ 禁用测试交换文件失败: %s\n", strerror(errno));
        }
        
        // 删除交换文件
        if (unlink(test_swap_file) == 0) {
            printf("  ✓ 删除测试交换文件成功\n");
        } else {
            printf("  ✗ 删除测试交换文件失败: %s\n", strerror(errno));
        }
    }
    
    // 显示性能测试总结
    printf("\n=== 性能测试总结 ===\n");
    printf("1. 交换空间性能指标:\n");
    printf("   - 交换I/O速度\n");
    printf("   - 内存分配延迟\n");
    printf("   - 系统响应时间\n");
    
    printf("\n2. 性能优化建议:\n");
    printf("   - 使用SSD作为交换空间\n");
    printf("   - 合理设置交换空间大小\n");
    printf("   - 调整交换倾向参数 (swappiness)\n");
    
    printf("\n3. 监控要点:\n");
    printf("   - 交换空间使用率\n");
    printf("   - 系统负载情况\n");
    printf("   - 内存使用趋势\n");
    
    return 0;
}

int main() {
    return demo_swap_performance_test();
}

swapon/swapoff 使用注意事项

系统要求:

  1. 内核版本: 支持交换空间管理的Linux内核
  2. 权限要求: 需要root权限
  3. 架构支持: 支持所有主流架构

文件要求:

  1. 权限: 交换文件权限必须为600
  2. 格式: 必须使用mkswap初始化
  3. 大小: 建议为页面大小的倍数

错误处理:

  1. EPERM: 权限不足
  2. EINVAL: 无效参数
  3. EBUSY: 交换空间正在使用中
  4. ENOMEM: 内存不足

安全考虑:

  1. 文件权限: 确保交换文件权限正确
  2. 数据安全: 交换空间可能包含敏感数据
  3. 系统稳定性: 不当的交换管理可能影响系统稳定性

最佳实践:

  1. 权限检查: 执行前检查是否具有足够权限
  2. 错误处理: 妥善处理各种错误情况
  3. 资源清理: 及时清理临时交换文件
  4. 监控管理: 监控交换空间使用情况
  5. 性能调优: 根据系统特性调整交换策略

交换空间相关常量和参数

交换标志:

// swapon标志(通常为0)
#define SWAP_FLAG_PREFER     0x8000  // 优先使用
#define SWAP_FLAG_DISCARD    0x10000 // 启用discard

系统参数:

// /proc/sys/vm/swappiness (0-100)
// 控制内核使用交换空间的倾向
echo 10 > /proc/sys/vm/swappiness  // 降低交换倾向

相关文件和命令

系统文件:

  • /proc/swaps: 当前交换空间信息
  • /proc/meminfo: 内存使用信息
  • /proc/sys/vm/swappiness: 交换倾向参数

相关命令:

# 显示交换空间信息
cat /proc/swaps
swapon --show

# 显示内存使用情况
free -h
cat /proc/meminfo

# 管理交换空间
swapon /swapfile
swapoff /swapfile
mkswap /swapfile

常见使用场景

1. 系统管理:

// 动态添加交换空间以应对内存不足
swapon("/tmp/emergency_swap", 0);

2. 性能调优:

// 为不同存储设备设置不同的交换优先级
swapon("/dev/ssd_swap", priority << 16);

3. 资源监控:

// 监控交换空间使用情况并动态调整
if (swap_usage > 90%) {
    // 添加更多交换空间
    swapon("/tmp/additional_swap", 0);
}

总结

swapon 和 swapoff 是Linux系统中重要的内存管理函数,提供了:

  1. 动态管理: 可以动态启用和禁用交换空间
  2. 灵活配置: 支持不同的交换文件和设备
  3. 优先级控制: 可以设置交换空间的使用优先级
  4. 系统集成: 与Linux内核深度集成

通过合理使用这些函数,可以构建灵活的内存管理系统,提高系统的稳定性和性能。在实际应用中,需要注意权限要求、错误处理和系统稳定性等关键问题。

此条目发表在linux文章分类目录,贴了标签。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注