iOS图片占内存大小与什么有关?

1. 问:一张图片所占内存大小跟什么有关?

图片所占内存大小,与图片的宽高有关

我们平时看到的png、jpg、webp这些图片格式,其实都是图片压缩格式。通过对应的算法来优化了大小以节省网络传输与本地保存所需的资源。
但是当我们加载图片到内存中将要显示出来的时候是不能使用压缩格式,这样就不能显示图片了。

计算机依赖每一个像素点中的数据来显示图片。
例如iOS中的UIImange的每个像素点是由red+green+blue 三原色在加上alpha透明度组成的。
三原色每一个的范围在0 ~ 255所以需要1个字节来存储一个值的大小。
那么一个像素点的颜色就需要3个字节
再加上需要alpha的大小,alpha的范围是0~100 也是以1个字节来存储的。
所以一个像素点就需要4个字节来存储

疑问:
像素一定是RGB表示?必须是占4个字节?
像素会不会其他格式表示,从而造成所占字节数不同?

在这里插入图片描述

这样算来,一个image的size为100100,每个像素点占4个字节,那么
该图片的内存占用为:100
1004byte = 40000btye = 40001024KB

测试:

取一个图片,其大小是750x844
在这里插入图片描述

在这里插入图片描述

- (void)testImageSize
{
    UIImageView *imageView = [[UIImageView alloc] init];
    imageView.frame = CGRectMake(100, 100, 100, 100);
    imageView.image = [UIImage imageNamed:@"yz_life_share_gift_top_bg_image_2"];
    [self.view addSubview:imageView];
    
    //获取
    //The width, in pixels, of the specified bitmap image (or image mask).
    //指定位图图像(或图像掩码)的宽度(以像素为单位)。
    CGFloat imageWidth = CGImageGetWidth(imageView.image.CGImage);
    CGFloat imageHeight = CGImageGetHeight(imageView.image.CGImage);
    
    CGFloat imageMemorySize = imageHeight * imageWidth * 4 /1024/1024;
    NSLog(@"%f, %f, %f", imageWidth, imageHeight, imageMemorySize);
    //750.000000, 844.000000, 2.414703
    
    //或者
    //The number of bytes used in memory for each row of the specified bitmap image (or image mask).
    //指定位图图像(或图像掩码)的每一行在内存中使用的字节数。
    CGFloat bytesPerRow = CGImageGetBytesPerRow(imageView.image.CGImage);
    CGFloat imageMemorySize2 = imageHeight * bytesPerRow/1024/1024;
    NSLog(@"%f, %f, %f", bytesPerRow, imageHeight, imageMemorySize2);
    //3000.000000, 844.000000, 2.414703
}

也就是,一张11KB大小的图片,在内存中占用的内存大小是2.414703M

还是蛮大的

图片的大小?

首先,宽高,是指的图片本身的宽高,而不是mageView被设置的size

而图片的大小,可以用 单位为厘米 去测量,也可以用 单位为像素 去测量
比如100cm * 100cm大小的图片,其换算成像素为单位,并不是100px * 100px

本文章里,所讲的图片的大小,其实是以像素为单位的图片的大小

iOS uiimage内存占用大小计算

2. 问:为什么图片占用这么大的内存,而不是图片的原始大小?

这就要从图片格式来说,我们通常用的图片格式如:png和jpeg等,这些格式的图片都是压缩的位图格式,不能直接渲染展示在屏幕上,所以就需要在渲染到屏幕之前,需要将图片解压缩,得到图片的原始像素数据,过程如下:
在这里插入图片描述
即:Data Buffer、Image Buffer、Frame Buffer
Data Buffer 是存储在内存中的原始数据,图像可以使用不同的格式保存,如 jpg、png。是Image 的文件内容。
Image Buffer 是图像在内存中的存在方式,用于存放图像具体素点信息。Image Buffer 的大小和图像的大小成正比。
Frame Buffer 和 Image Buffer 内容相同,不过其存储在 vRAM(video RAM)中,而 Image Buffer 存储在 RAM 中。
解码就是从 Data Buffer 生成 Image Buffer 的过程。Image Buffer 会占用带宽上传到 GPU 成为 Frame Buffer,最后GPU负责使用 Frame Buffer用于更新显示区域。

3. 问:如何避免图片占用内存过大的问题呢?

方法一:

使用[UIImage imageNamed:@""];这种方式加载图片的话,图片会缓存在内存里面,不被释放
如果遇到频率使用低的图片、图片大的图片,建议使用[UIImage imageWithContentsOfFile:nil];这种方式加载图片

使用imageName:加载图片

  • 加载到内存当中会一直存在内存当中,(图片)不会随着对象的销毁而销毁。
  • 加载进去图片后,占用的内存归系统管理,我们是无法管理的。
  • 相同的图片是不会重复加载的
  • 加载到内存中占据的内存较大

使用imageWithContentOfFile:加载图片

  • 加载到内存中占据的内存较小
  • 相同的图片会被重复加载到内存当中
  • 加载的图片会随着对象的销毁而销毁

[UIImage imageNamed:]加载图片,与imageWithContentOfFile:加载图片有什么区别?

方法二:

使用UIGraphicsImageRenderer的API

如果ImageView的本身就是固定的200x200,加载800x800的图片会有什么问题?
答案:载入800x800的图片用到200x200的控件上是很浪费内存。需要消耗的内存大小800x800x4bit。

解决方案:在使用前把图片调整到需要的大小

因此,我们使用UIGraphicsImageRenderer,将图片大小调整为用户自己所需要的大小,以减少内存的使用

UIImage *image = [UIImage imageNamed:@"yz_life_share_gift_top_bg_image_2"];
//调用,或者直接传image.size.width
image = [self resiImage:image size:CGSizeMake(100, 100)];
imageView.image = image;

//方法
- (UIImage*)resiImage:(UIImage *)image size:(CGSize)size{
    UIGraphicsImageRenderer *re = [[UIGraphicsImageRenderer alloc]initWithSize:size];
    return [re imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
        [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
    }];
}

打印结果:
300.000000, 300.000000, 0.343323
1216.000000, 300.000000, 0.347900

即,使用这种方法,可以将图片内存由原来的2.41M变为0.35M

但,当图片设置为300 * 300大小时,打印为
900.000000, 900.000000, 3.089905
3616.000000, 900.000000, 3.103638
此时,图片所占内存变为了3.1M,比原来2.41M还大。。。

也就是UIGraphicsImageRenderer适合大的图片放在小view上面这种情况

iOS Image 内存优化
UIGraphicsImageRenderer图片渲染优化


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vant4中如何修改Dialog弹框内容的字体大小

最近在开发一个移动端的需求,用的UI组件库是vant4 简单地总结一下,如何修改Dialog弹框内容的字体大小 我们先看一下Dialog弹框简单的使用 import { showConfirmDialog } from vant;showConfirmDialog({title: 标题,message:如果解决方法是丑陋的&#…

抖音视频无水印下载软件|视频批量提取工具

视频无水印下载软件 随着视频平台上涌现出越来越多精彩的视频内容,很多用户希望能够下载自己喜爱的视频进行保存或分享。为了满足用户需求,我们推出了专业的视频无水印下载软件,让您可以轻松快捷地获取喜欢的视频内容。以下是该软件的安装教…

Sealos 云开发:Laf 出嫁了,与 Sealos 正式结合!

千呼万唤始出来,Laf 云开发最近已正式与 Sealos 融合,入住 Sealos!大家可以登录 Sealos 公有云 体验和使用,现在正式介绍一下 Sealos 云开发。 Sealos 云开发是什么? 如图,我们把 Laf 融合到 Sealos 中去了…

MySQL如何用phpMyAdmin创建定时任务事件来执行SQL语句删除_edit_lock和_edit_last?

前面跟大家分享了『WordPress如何批量删除wp_postmeta数据表无用的_edit_lock和_edit_last数据?』和『宝塔面板在计划任务中怎么执行SQL语句删除_edit_lock和_edit_last?』,但是有些站长并不是使用宝塔面板,那么我们如何时间定时删…

AIGC:让生成式AI成为自己的外脑

前言 在数字化浪潮席卷全球的今天,人工智能(AI)已经渗透到了我们生活的方方面面。其中,生成式AI以其独特的魅力,正逐渐改变我们与世界的交互方式。AIGC(人工智能生成内容)作为生成式AI的重要应用…

灯塔:CSS笔记(4)

伪类选择器: 1.作用与优势: 1.作用:根据元素在HTML中的结构关系查找元素 2.优势:减少对于HTML中类的依赖,有利于保持代码的整洁 3.场景:常用于查找某父级选择器中的子元素 2.选择器 选择器说明E:first-c…

数据库的基本概念和安装MYSQL数据库

目录 一、数据库的发展 1、文件管理系统的缺点 2、数据库管理系统DBMS的优点 3、数据库管理系统(DBMS) 3.1DBMS的功能 3.2DBMS的工作模式 4、数据库系统的发展 5、数据库管理系统的架构 6、数据库管理系统分类 二、RDBMS关系型数据库的基本介绍…

软考 网工 每日学习打卡 2024/3/19

学习内容 第8章 网络安全 本章主要讲解网络安全方面的基础知识和应用技术。针对考试应该掌握诸如数据加密、报文认 证、数字签名等基本理论,在此基础上深入理解网络安全协议的工作原理,并能够针对具体的 网络系统设计和实现简单的安全解决方案。 本章共有…

Java学习笔记21——使用JDBC访问MySQL数据库

JDBC(Java Database Connectivity,Java数据库连接)是应用程序编程借口(API),描述了一套访问关系数据库的标准Java类库。可以在程序中使用这些API,连接到关系数据库,执行SQL语句&…

由浅到深认识C语言(7):预处理二进制

该文章Github地址:https://github.com/AntonyCheng/c-notes 在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.csdn…

Oracle19C静默安装教程

一、安装前的准备 1、安装Linux操作系统 红帽Linux安装教程 2、配置网络源或者本地源 网络源:网络源配置方法 本地源:本地源配置方法 3、hosts文件配置 配置hostname: hostnamectl set-hostname p19c配置hosts文件: cat &…

从零开始写 Docker(七)---实现 mydocker commit 打包容器成镜像

本文为从零开始写 Docker 系列第七篇,实现类似 docker commit 的功能,把运行状态的容器存储成镜像保存下来。 完整代码见:https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识: 核心原…

多个线程交替打印ABC

多个线程交替打印ABC package 多个线程交替打印ABC;import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier;/*** Created with IntelliJ IDEA.** Author: AlenXu* Date: 2024/03/20/10:10* Description:*/ public class ThreadLoopP…

数字功放VS模拟功放,选择适合你的音频解决方案

数字功放和模拟功放是音频系统中常用的两种功放技术,适用于不同的音频应用,都具有各自的优势和特点。本文将为您详细介绍数字功放和模拟功放的差异,并帮助您找到适合自己的音频解决方案。 1、数字功放是一种利用数字信号处理技术的功放。它将…

0基础 三个月掌握C语言(13)

数据在内存中的存储 整数在内存中的存储 在讲解操作符时 我们就已经学习了该部分的内容 这里我们回顾一下 整数的二进制表示方法有三种:原码 反码 补码 有符号的整数(unsigned) 三种表达方式均有符号位和数值位两部分 最高位的一位被当…

【C语言步行梯】C语言实现扫雷游戏(含详细分析)

🎯每日努力一点点,技术进步看得见 🏠专栏介绍:【C语言步行梯】专栏用于介绍C语言相关内容,每篇文章将通过图片代码片段网络相关题目的方式编写,欢迎订阅~~ 文章目录 需求分析具体实现主函数体菜单实现游戏实…

AI预测福彩3D第14弹【2024年3月20日预测--新算法重新开始计算第11次测试】

今天继续对第一套算法进行测试。废话不多说了,直接上分析出的图表,再上结果。 最终,经过研判分析,2024年3月20日福彩3D的七码预测结果如下: 百位:7 8 4 3 5 6 9(1换9) 十位:5 4 3 6 1 2 0(07分一…

day14-SpringBoot 原理篇

一、配置优先级 SpringBoot 中支持三种格式的配置文件: 注意事项 虽然 springboot 支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置 (yml 是主流)。 配置文件优先级排名(从高到低&…

事务同步管理器TransactionSynchronizationManager

事务同步管理器的使用场景: 同步涉及的资源包括:SqlSession & Connection。同步资源核心目的是线程共享,意味着必须跟线程绑定。同步资源伴随着线程生存或者消亡,意味着线程结束之前必须手动清除其绑定的资源。事务同步管理器…

基于SpringBoot+Redis实现接口限流

前言 业务中需要对一些接口进行限流处理&#xff0c;防止机器人调用或者保证服务质量&#xff1b; 实现方式 基于redis的lua脚本 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis&…