操作系统笔记之内存映射

news2024/11/24 16:25:14

操作系统笔记之内存映射

—— 杭州 2024-02-04

在这里插入图片描述

code review!

文章目录

  • 操作系统笔记之内存映射
    • 一.内存映射概念
      • 1. 文件映射到内存 (Memory-Mapped Files)
      • 2. 虚拟内存管理 (Virtual Memory Management)
      • 3. 内存映射I/O (Memory-Mapped I/O)
      • 4. 图形处理 (Graphics Processing)
      • 5. 数据库内存映射 (Database Memory Mapping)
      • 6. 分布式内存映射 (Distributed Memory Mapping)
    • 二.虚拟内存管理 (Virtual Memory Management)
        • 1. 虚拟地址空间
        • 2. 物理地址空间
        • 3. 页
        • 4. 页表
        • 5. 分页机制
        • 6. TLB (Translation Lookaside Buffer)
        • 7. 页错误(Page Fault)
    • 三.文件映射到内存 (Memory-Mapped Files)
      • 内存映射的原理
      • 内存映射的优势
      • 内存映射的劣势
      • 如何使用内存映射
      • 传统的文件读写API:
      • 内存映射方式:
      • ChatGPT——mmap()详解
      • 基本用法
      • 示例

一.内存映射概念

内存映射(Memory Mapping)是一个较为广泛的概念,它可以在不同的计算机科学领域内有不同的应用和含义。以下是内存映射的几个常见用途:

1. 文件映射到内存 (Memory-Mapped Files)

这是内存映射最常见的用途之一,涉及将磁盘上的文件内容映射到进程的地址空间。这样,文件可以像访问内存一样被访问,而不需要显式地执行读写操作。这通常用于提高文件I/O操作的性能,因为它允许操作系统利用虚拟内存管理来进行优化。

2. 虚拟内存管理 (Virtual Memory Management)

在虚拟内存系统中,内存映射描述了虚拟地址空间到物理内存的转换过程。操作系统通过内存映射来确保每个进程有自己独立的地址空间,并将这些地址映射到物理RAM或者磁盘上的交换空间。

3. 内存映射I/O (Memory-Mapped I/O)

在硬件设计和低级编程中,内存映射I/O是指将设备寄存器的I/O地址映射到程序的地址空间,使得设备I/O可以使用普通的内存访问指令进行。这简化了对硬件设备的编程,因为它允许程序员使用对内存的操作来控制硬件设备。

4. 图形处理 (Graphics Processing)

在图形处理中,内存映射可以指显存(GPU内存)和系统内存之间的映射。这使得CPU可以访问和操作GPU内存中的数据,例如纹理和帧缓冲区。

5. 数据库内存映射 (Database Memory Mapping)

某些数据库系统使用内存映射技术来提高访问持久化数据的效率。通过将数据库文件映射到内存,数据库查询和操作可以更快地执行,因为它们直接在内存中进行。

6. 分布式内存映射 (Distributed Memory Mapping)

在分布式系统中,内存映射也可以指不同机器之间共享内存空间的技术。这允许构建高性能的分布式应用程序,使得远程数据可以像本地内存一样被访问和修改。

内存映射是一个多面的概念,它的具体含义依赖于上下文。在不同的系统和应用程序中,内存映射的机制和目的可能会有所不同。

二.虚拟内存管理 (Virtual Memory Management)

虚拟内存管理是操作系统中用于抽象物理内存的一种机制,它允许每个程序像拥有一台独立的、拥有足够内存的计算机一样运行,即使实际的物理内存可能不足以同时容纳所有运行的程序。

这里的"内存映射"指的是虚拟地址(由程序使用)到物理地址(RAM中的实际位置)的转换。操作系统通过维护一张映射表(页表)来管理这个转换过程。以下是虚拟内存管理的关键概念和组件:

1. 虚拟地址空间
  • 虚拟地址空间是指一个程序可见的内存范围,这个范围由操作系统管理,对程序来说就像是它独占的内存。
  • 每个程序都有自己的虚拟地址空间,它是连续的,从程序的角度看不会感知到物理内存的实际分布情况。
2. 物理地址空间
  • 物理地址空间是实际的RAM内存地址。
  • 物理内存通常是不连续分配给程序的,因为它被所有程序和操作系统共享。
3. 页
  • 虚拟内存和物理内存被分割成大小相同的块,称为"页"(在虚拟内存中)和"页帧"(在物理内存中)。
  • 页的大小可以根据系统设计而不同,常见的大小有4KB、2MB等。
4. 页表
  • 页表是操作系统维护的数据结构,用于跟踪虚拟页和物理页帧之间的映射关系。
  • 当程序访问其虚拟地址空间时,操作系统使用页表来找到对应的物理地址。
5. 分页机制
  • 分页机制是一种内存管理技术,它允许虚拟内存被分割为多个页,并且每个页可以单独映射到物理内存中的任意位置。
  • 这种技术也支持"懒加载"(按需加载)和"交换"(或"换出"),即将不活跃的页移动到磁盘上的交换空间,腾出物理内存给其他程序使用。
6. TLB (Translation Lookaside Buffer)
  • TLB是一种缓存,它存储最近使用的页表条目,以加快虚拟地址到物理地址的转换过程。
  • TLB命中(找到缓存的页表条目)速度快于完整的页表查找。
7. 页错误(Page Fault)
  • 当程序访问的虚拟地址没有映射到物理内存时,会发生页错误中断。
  • 操作系统必须处理这个中断,通常是通过将所需的数据从磁盘加载到内存中,并更新页表来解决。

通过虚拟内存管理,操作系统提供了一种有效的方式来利用有限的物理内存资源,并且为每个程序提供了一种看似拥有无限内存资源的环境。这大大简化了程序设计,并提高了系统的稳定性和安全性。

三.文件映射到内存 (Memory-Mapped Files)

内存映射(Memory Mapping)是一种文件I/O处理的方法,它将文件内容映射到进程的地址空间,使得程序可以像访问内存一样对文件进行读写,而不必使用传统的文件读写API。内存映射可以提高文件操作的性能,特别是对于大文件的处理。

内存映射的原理

当一个文件被内存映射后,操作系统会保留进程地址空间中的一段区域,这段区域的地址范围会与文件内容建立直接的映射关系。进程可以通过指针直接访问这段内存,操作系统负责将对应的文件数据加载到物理内存中,并在必要时同步到磁盘文件。

内存映射的具体实现依赖于操作系统的虚拟内存管理机制。当进程访问映射内存中某个位置的数据时,如果该数据尚未加载到物理内存,则会触发一个缺页中断(page fault),操作系统随后将文件对应部分的数据加载到内存中,并重新开始指令的执行。

内存映射的优势

  1. 性能提升:避免了传统文件I/O的系统调用开销和用户空间与内核空间之间的数据拷贝。
  2. 简化编程模型:程序员可以使用指针操作文件,无需调用read/write等文件操作函数。
  3. 便于共享:内存映射的文件可以被多个进程共享,便于实现进程间通信。
  4. 按需加载:文件数据按需加载到内存,而不是一次性全部加载,可以有效利用内存资源。
  5. 自动同步:操作系统会在适当的时候将修改后的内存数据同步回磁盘文件。

内存映射的劣势

  1. 内存消耗:映射大文件时,如果同时访问文件的多个部分,可能会消耗大量的物理内存。
  2. 文件大小限制:对于32位系统,内存映射的文件大小受到地址空间限制,通常不能超过2GB。
  3. 复杂的错误处理:内存映射文件在访问时可能会因为I/O错误导致程序异常终止。

如何使用内存映射

在Unix-like系统中,可以通过mmap()系统调用实现内存映射。以下是一个简单的示例:

#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

int main() {
    // 打开文件
    int fd = open("example.txt", O_RDONLY);
    struct stat sb;
    if (fd == -1) {
        // 错误处理
    }

    // 获取文件的属性
    if (fstat(fd, &sb) == -1) {
        // 错误处理
    }

    // 执行内存映射
    char *mapped = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (mapped == MAP_FAILED) {
        // 错误处理
    }

    // 现在可以通过mapped指针访问文件内容

    // 解除内存映射
    if (munmap(mapped, sb.st_size) == -1) {
        // 错误处理
    }

    close(fd);
    return 0;
}

在Windows操作系统中,内存映射可以通过CreateFileMapping和MapViewOfFile函数来实现。

内存映射在文件I/O密集型应用中非常有用,如数据库、文件系统以及需要高速文件处理的应用程序。然而,在使用时需要考虑到内存映射的各种限制,并实现适当的错误处理机制。

内存映射文件的工作原理如下:

  1. 文件映射:操作系统提供的内存映射API(如Windows的 CreateFileMappingMapViewOfFile,或者Unix/Linux的 mmap 函数)用来创建文件的内存映射。这个映射过程会将文件内容关联到进程的虚拟地址空间。

  2. 内存访问:一旦文件被映射,它就可以像普通的内存区域一样被访问。你可以通过指针来读写这块内存,操作系统会自动将这些读写操作转换为对文件的读写。

  3. 数据同步:对映射内存的更改可能会被延迟写入到实际的文件中,这取决于具体的同步策略。在某些情况下,开发者可能需要显式地告诉操作系统将更改立即写回文件(例如,使用 msync 函数)。

  4. 映射解除:完成对文件的操作后,应该解除文件的内存映射,释放资源。在Unix/Linux系统中,这通常通过 munmap 函数实现,在Windows中通过 UnmapViewOfFileCloseHandle 函数实现。

使用内存映射来读写文件的优势包括:

  • 性能提升:对于大文件操作,内存映射可以提高性能,因为它避免了传统的文件I/O操作中的系统调用和缓冲区管理开销。
  • 简化编码:开发者可以直接通过指针来读写文件数据,这种方式比传统的文件I/O API更直观简单。
  • 便于文件共享:映射文件可以被多个进程共享,为进程间通信提供了一种方便的机制。

需要注意的是,内存映射文件也有其局限性和风险:

  • 内存消耗:映射大文件到内存会消耗等量的虚拟地址空间,对于32位系统来说,这可能是个问题。
  • 文件大小变化:如果映射的文件在映射期间被外部过程修改,并且文件大小发生变化,可能会导致访问违规。
  • 数据一致性:确保内存中的更改及时同步到磁盘上,以避免数据丢失。

总之,内存映射文件提供了一种高效和便捷的文件访问方式,特别是对于需要频繁读写大型文件的应用程序。但同时,开发者需要理解其工作原理和潜在的风险。

让我们通过一个简单的例子来比较传统的文件读写API和内存映射方式。假设我们有一个文本文件,我们想要读取内容并修改其中的一些数据。

传统的文件读写API:

在C语言中,你可能会使用标准的文件I/O函数如 fopen, fread, fwrite, 和 fclose。以下是一个简单的例子,展示了如何使用这些API来读取和修改文件内容:

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *file;
    char buffer[1024];

    // 打开文件
    file = fopen("example.txt", "r+");
    if (file == NULL) {
        perror("Error opening file");
        return -1;
    }

    // 读取文件内容到缓冲区
    size_t bytes_read = fread(buffer, sizeof(char), sizeof(buffer), file);
    if (bytes_read == 0 && ferror(file)) {
        perror("Error reading file");
        fclose(file);
        return -1;
    }

    // 修改缓冲区中的数据
    buffer[0] = 'H'; // 仅示例:修改文件的第一个字符

    // 回到文件开始
    fseek(file, 0, SEEK_SET);

    // 将修改后的缓冲区写回文件
    if (fwrite(buffer, sizeof(char), bytes_read, file) != bytes_read) {
        perror("Error writing to file");
        fclose(file);
        return -1;
    }

    // 关闭文件
    fclose(file);
    return 0;
}

内存映射方式:

使用内存映射文件,你可以避免使用标准的文件I/O函数,而是通过映射文件到内存,直接像操作内存一样操作文件。以下是使用 mmap 在Linux上的一个示例:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd;
    struct stat sb;
    char *mapped;

    // 打开文件
    fd = open("example.txt", O_RDWR);
    if (fd == -1) {
        perror("Error opening file for writing");
        return -1;
    }

    // 获取文件的属性
    if (fstat(fd, &sb) == -1) {
        perror("Error getting the file size");
        close(fd);
        return -1;
    }

    // 执行映射
    mapped = mmap(0, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (mapped == MAP_FAILED) {
        perror("Error mapping the file");
        close(fd);
        return -1;
    }

    // 现在文件的内容就在mapped指针中
    // 修改映射区的数据,将反映到文件中
    mapped[0] = 'H'; // 仅示例:修改文件的第一个字符

    // 解除映射
    if (munmap(mapped, sb.st_size) == -1) {
        perror("Error un-mapping the file");
    }

    // 关闭文件
    close(fd);
    return 0;
}

在这个例子中,通过内存映射,我们可以直接通过 mapped 指针来访问和修改文件内容,就像它是程序的一部分内存一样。这种方法避免了使用缓冲区,也没有显式的读写操作。文件的读写操作是通过对内存的操作隐式完成的。

总结:

  • 传统方法:需要显式地读取数据到内存中的缓冲区,处理完后再显式写回文件。
  • 内存映射方法:通过将文件直接映射到进程地址空间,可以像操作内存一样操作文件,无需显式的读写调用。

ChatGPT——mmap()详解

mmap() 是一个 Unix/Linux 系统调用,它提供了一种将文件或其他对象映射到内存的方法。这允许程序员直接在内存中访问文件内容,就像它是一个数组一样,这样可以提高文件的访问速度,因为避免了传统的读写系统调用的开销。mmap() 通常用于文件的读取、写入,以及创建共享内存。

基本用法

这是 mmap() 函数的基本原型:

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);

参数说明:

  • addr: 指定映射区域的起始地址。通常传递 NULL 让系统自己选择地址。
  • length: 映射区域的长度。单位是字节。
  • prot: 指定映射区域的保护。可以是以下几个值的组合:
    • PROT_READ: 映射区域可被读取。
    • PROT_WRITE: 映射区域可被写入。
    • PROT_EXEC: 映射区域可执行代码。
    • PROT_NONE: 映射区域不能访问。
  • flags: 控制映射区域的特性。主要有以下几个选项:
    • MAP_SHARED: 对映射区域的修改会反映到被映射的文件上,并且对其他映射了同一个文件的进程可见。
    • MAP_PRIVATE: 对映射区域的修改不会影响原文件,而是创建一个写时复制的私有副本。
    • MAP_ANONYMOUS: 映射区域不是映射到具体的文件上,通常用于共享内存的创建。
  • fd: 被映射文件的文件描述符。对于匿名映射,该值通常设为 -1
  • offset: 文件映射的起始偏移量,必须是系统页面大小的整数倍。

返回值:成功时,mmap() 返回指向映射区域的指针。失败时,返回 MAP_FAILED(void *) -1),并设置 errno 以指示错误。

示例

这是一个使用 mmap() 映射文件并读取内容的简单示例:

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    const char *filepath = "example.txt";
    int fd = open(filepath, O_RDONLY);
    if (fd == -1) {
        perror("Error opening file for reading");
        exit(EXIT_FAILURE);
    }

    struct stat sb;
    if (fstat(fd, &sb) == -1) {
        perror("Error getting the file size");
        exit(EXIT_FAILURE);
    }

    char *map = mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
    if (map == MAP_FAILED) {
        close(fd);
        perror("Error mmapping the file");
        exit(EXIT_FAILURE);
    }

    // Now the file content is in memory and can be accessed via `map` pointer.
    for (size_t i = 0; i < sb.st_size; i++) {
        printf("%c", map[i]);
    }

    // Unmap and close the file.
    if (munmap(map, sb.st_size) == -1) {
        perror("Error un-mmapping the file");
    }
    close(fd);

    return 0;
}

在上面的代码中,我们首先打开了一个文件,然后使用 fstat() 获取文件的大小,接着使用 mmap() 创建一个文件内容的内存映射。文件的内容现在可以通过指针 map 访问。在处理完文件内容后,我们使用 munmap() 删除映射,并关闭文件。

注意,使用 mmap() 时必须小心地管理内存和文件的描述符,避免内存泄漏或文件描述符泄漏等问题。此外,当使用 MAP_SHARED 标志时,对映射区域的改变可能会影响到原文件,这在多进程间共享数据时非常有用,但在不同步的情况下也可能导致数据不一致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1434052.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AI】手把手教你用SSH与GitHub仓库建立连接

在使用原来的账户密码方式建立连接时&#xff0c;发现终端提示&#xff1a; remote: Support for password authentication was removed on August 13, 2021. remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#…

Spring框架——主流框架

文章目录 Spring(轻量级容器框架)Spring 学习的核心内容-一图胜千言IOC 控制反转 的开发模式Spring快速入门Spring容器剖析手动开发- 简单的 Spring 基于 XML 配置的程序课堂练习 Spring 管理 Bean-IOCSpring 配置/管理 bean 介绍Bean 管理包括两方面: Bean 配置方式基于 xml 文…

【深度学习理论】持续更新

文章目录 1.统计学习理论 1.统计学习理论 统计学习理论&#xff0c;一款适合零成本搞深度学习的大冤种的方向 从人类学习到机器学习的对比&#xff08;学习的过程分为归纳和演绎 &#xff09;&#xff0c;引出泛化和过拟合的概念。 如何表示归纳的函数规律呢&#xff1f;以监督…

基础数学问题整理

最近刷了一些关于基础数学问题的题目&#xff0c;大致是关于组合数、分解质因数还有一些思维题&#xff0c;题目来自洛谷的【数学1】基础数学问题 - 题单 - 洛谷&#xff0c;很多思路还是之前没有见过的&#xff0c;都是简单到一般难度的题目&#xff08;橙、题、绿题&#xff…

远程桌面时连接不上远程计算机是什么问题

在服务器上搭建网络程序时&#xff0c;我们经常会有需要远程连接上服务器进行相关操作&#xff0c;有些用户在远程桌面的时候&#xff0c;有时会有遇上无法连接到远程计算机的情况。 很多用户都曾遇到在远程桌面时出现“未启用对服务器的远程访问”、“远程计算机已关闭”、“…

AIGC技术讲解以及应用的落地

简介 近期&#xff0c;火爆的“AI绘画”、图片转AI图&#xff0c;智能聊天软件ChatGPT&#xff0c;引起了人们广泛关注。人工智能潜力再次被证明&#xff0c;而这三个概念均来自同一个领域&#xff1a;AIGC。AIGC到底是什么&#xff1f;为什么如此引人关注&#xff1f;AIGC能产…

代码生成器(新):mybatis-plus-generator使用指南

代码生成器&#xff08;新&#xff09;官网 后端代码&#xff1a;点击查看 LearnElementUiAndSpringBoot 提醒&#xff1a;LearnElementUiAndSpringBoot下载完后&#xff0c;在运行调试 Main.java里的main方法之前&#xff0c;除了utils包和Main.java文件&#xff0c;其他包需…

rac二节点实例redo故障无法启动修复

问题描述 节点二由于redo故障问题无法正常启动 目前节点二为mount状态&#xff0c;open报错。alter database open ERROR at line 1: ORA-00322: log 28 of thread 2 is not current copy ORA-00312 查询v$log视图发现节点二的redo log组没有状态为current的日志组。大概…

今年过年都有哪些方式?其中又有什么商机

古往今来&#xff0c;春节都是十分重要的节日&#xff0c;它承载着家庭团聚、祭祖祈福的重要意义&#xff0c;然而在今年&#xff0c;年轻人过年的方式不那么传统&#xff0c;今天媒介盒子就来和大家聊聊&#xff1a;今年过年都有哪些方式&#xff1f;其中又有什么商机。 一、 …

电商服务类指标分析(3)——用户反馈模块指标

前段时间做了一个电商服务类项目&#xff0c;与业务一起梳理了部分指标&#xff0c;这些指标便于了解电商服务&#xff0c;现在做一个整理和回顾。 电商服务类指标可以分为五大类&#xff0c;涵盖了服务从售前、履约、售后、用户反馈、监控预警这样一条链路的内容。 本篇文章来…

大数据知识图谱之深度学习——基于BERT+LSTM+CRF深度学习识别模型医疗知识图谱问答可视化系统

文章目录 大数据知识图谱之深度学习——基于BERTLSTMCRF深度学习识别模型医疗知识图谱问答可视化系统一、项目概述二、系统实现基本流程三、项目工具所用的版本号四、所需要软件的安装和使用五、开发技术简介Django技术介绍Neo4j数据库Bootstrap4框架Echarts简介Navicat Premiu…

实习日志13

1.早上试了一下社区里的东西 1.1.插件&#xff0c;可交互页面 垃圾插件&#xff0c;显示的html不支持我的html&#xff0c;js都加载不出来 1.2.插件&#xff0c;文件上传 硬件给的是用websocket交互的&#xff0c;没有文件下载接口 2.打算自己搞了&#xff0c;试试用cooki…

360,这次你真行:流氓耍到外国佬身上,凌晨1点让我笑岔气

天下&#xff0c;苦流氓软件久矣 在数字世界中&#xff0c;我们常常遭遇一些令人头疼的问题&#xff0c;其中尤以大厂软件的牛皮癣特性为甚。这些软件不仅捆绑安装广告推广&#xff0c;而且手段无所不用其极&#xff0c;让用户感到无可奈何。 在此&#xff0c;我不得不提及四…

Linux内存管理:(十二)Linux 5.0内核新增的反碎片优化

文章说明&#xff1a; Linux内核版本&#xff1a;5.0 架构&#xff1a;ARM64 参考资料及图片来源&#xff1a;《奔跑吧Linux内核》 Linux 5.0内核源码注释仓库地址&#xff1a; zhangzihengya/LinuxSourceCode_v5.0_study (github.com) 外碎片化发生时&#xff0c;页面分配…

2024年全球手机市场复苏 传音打响出海品牌进阶之战

2024年智能手机将迎来新一轮“增长季”。根据市场研究机构TechInsights的最新预测&#xff0c;2024年全球智能手机市场将恢复低个位数的增长。对广大手机厂商来说&#xff0c;这无疑是个好消息&#xff0c;但如何在逐渐回暖却竞争激烈的市场中站稳脚跟就需要他们“各显神通”了…

【Java EE】----Spring框架创建和使用

1.Spring框架创建 创建一个maven项目 添加Spring框架支持 <dependencies> 上下文<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.3.RELEASE</version></depende…

云打印服务未启动是什么情况?云打印服务未启动怎么解决?

随着互联网技术的发展&#xff0c;很多“云概念”也开始火热起来。这其中&#xff0c;最适合办公人群和学生人群的“云打印”概念也受到了追捧。目前市场上提供的云打印服务有很多&#xff0c;但是最近出现了较多云打印服务的问题。那么今天小易就带大家来了解一下&#xff0c;…

机器视觉系统设计:视觉系统中的成像基准

开发视觉系统的一个重要活动是验证其部署是否符合工程规范。一个成功的视觉应用程序的两个特点是它无需工程师干涉情况下正常工作了多长时间&#xff0c;以及它的维护和复制部署是多么简易。实现所有如上所述目标的一个关键步骤是确定视觉系统的基准。 在这里使用的上下文中&a…

LeetCode_19_中等_删除链表的倒数第N个结点

文章目录 1. 题目2. 思路及代码实现&#xff08;Python&#xff09;2.1 计算链表长度2.2 栈 1. 题目 给你一个链表&#xff0c;删除链表的倒数第 n n n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a; h e a d [ 1 , 2 , 3 , 4 , 5 ] , n…

Stable Diffusion 模型下载:RealCartoon-Anime - V10

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十 下载地址 模型介绍 这个检查点是从 RealCartoon3D 检查点分支出来的。它的目标是产生更多的“动漫”风格&#xff0c;因为我喜欢动漫。:)我知道有很多人做得很好&#xff08;比如aniw…