内存管理详解

news/发布时间2024/5/16 10:29:04

一些相关

【iOS】内存管理

什么是内存?

冯诺依曼结构

在这里插入图片描述
冯诺依曼结构中,存储器存放着程序的指令和数据,在程序运行时提供给CPU使用。

冯诺伊曼结构的瓶颈

CPU的运算速度远远大于了访存的速度,所以要找到一个速度、容量和成本都折中的方式 —— 存储器分层。

存储器分层

  • L0是寄存器,读写速度最快,是CPU组成部分之一;L1 - L3的高速缓存速度比主存更快,集成在CPU芯片内部
  • L5 - L6是设备成本较便宜且存储容量大的存储设备,但是存储速度低。
  • L4的主存也就是我们所说的内存,是一个设备成本与存储速度、存储容量都折中的存储设备。可见内存是一个外存与CPU之间的桥梁。
    在这里插入图片描述

内存

一个设备的RAM的大小,例如iPhone14ProMax的运行内存就是8GB
内存 = 主存 = 运行内存 = RAM

操作系统层面的内存管理

内存管理的概述:在软件运行时对计算机内存资源的分配和使用的技术。主要目的是高效、快速的分配,并且在合适的时候释放和回收内存资源。

CPU寻址方法

  • 物理寻址:CPU直接通过物理地址去访问内存。
  • 虚拟寻址:CPU通过访问虚拟地址,经过虚拟内存地址到物理内存地址的翻译获得物理地址,才能访问到对应的内存。

CPU是如何访问内存的呢?最简单直接的方式就是物理寻址,也就是CPU直接通过物理地址去访问内存,但物理寻址最大的一个问题就是地址空间缺乏保护:直接暴露物理地址,进程可以访问到任何物理地址,这是非常危险的,故引入了虚拟寻址。虚拟寻址就是CPU通过访问虚拟地址,经过虚拟内存地址到物理内存地址的翻译获得物理地址,才能访问到对应的内存,这个翻译过程由CPU的内存管理单元(MMU)完成。

虚拟内存

在虚拟地址到物理地址的翻译过程中可以增加一些权限判定,对地址空间进行保护,操作系统为每个进程提供了一个独立的、私有的、连续的地址空间,这就是虚拟内存。虚拟内存保护了进程的地址空间,使得进程之间互不干扰。
对于进程而言,它可见的部分只有虚拟内存,但实际上虚拟内存除了映射到物理内存以外,还有可能映射到磁盘,当物理内存的空间不足时,可以将部分内存数据交换到磁盘,也就是内存交换机制,有了该机制后,虚拟内存就可以利用磁盘拓展内存空间。
在这里插入图片描述

应用层面(iOS)的内存管理

iOS使用虚拟内存机制,但大多数移动设备包括iOS在內使用闪存,不存在内存和磁盘的交换,因此不支持内存交换机制。当内存不够用时,iOS会发出内存警告,didReceiveMemoryWarning方法就是在内存警告时会被触发,此时APP会清理一些不必要的内存来释放一定空间,当释放过后内存还是不够用时,就会发生OOM崩溃。在ios app maximum memory budget上统计了单个APP能够使用的最大内存,以iPhone12Pro为例,总共可用内存为5703MB,单个APP的可用内存达到了3054MB,占比54%,可以看出单个APP要发生OOM崩溃,绝大多数情况都是程序本身出现了问题。因此,合理控制APP的内存是至关重要的事情,应该尽可能的减少内存占用,并对内存警告以及 OOM 崩溃做好防范。

  1. iOS使用虚拟内存机制
  2. 没有内存交换机制
  3. 内存有限,但单个APP可用内存大
  4. 当内存不够用时,会触发内存警告

Clean Memory & Dirty Memory

对于一般的操作系统,Clean Memory可以理解为是能够进行Page Out的部分,但是因为iOS不存在内存交换的机制,所以对于iOS来说,Clean Memory指的是能被重新创建的内存,例如未写入数据的内存。

int *array = malloc(200 * sizeof(int));
array[0] = 32
array[199] = 64

iOS 内存管理

  • 说明内存和内存管理是什么
  • 介绍iOS的内存管理
  • 结合业务代码一起看
    什么是内存?
    冯诺依曼结构
    [图片]
    冯诺依曼结构中,存储器存放着程序的指令和数据,在程序运行时提供给CPU使用。
    冯诺伊曼结构的瓶颈
    CPU的运算速度远远大于了访存的速度,所以要找到一个速度、容量和成本都折中的方式 —— 存储器分层。
    存储器分层
  • L0是寄存器,读写速度最快,是CPU组成部分之一;L1 - L3的高速缓存速度比主存更快,集成在CPU芯片内部
  • L5 - L6是设备成本较便宜且存储容量大的存储设备,但是存储速度低。
  • L4的主存也就是我们所说的内存,是一个设备成本与存储速度、存储容量都折中的存储设备。可见内存是一个外存与CPU之间的桥梁。
    [图片]
    内存
    一个设备的RAM的大小,例如iPhone14ProMax的运行内存就是8GB
    内存 = 主存 = 运行内存 = RAM
    操作系统层面的内存管理
    内存管理的概述:在软件运行时对计算机内存资源的分配和使用的技术。主要目的是高效、快速的分配,并且在合适的时候释放和回收内存资源。
    CPU寻址方法
  • 物理寻址:CPU直接通过物理地址去访问内存。
  • 虚拟寻址:CPU通过访问虚拟地址,经过虚拟内存地址到物理内存地址的翻译获得物理地址,才能访问到对应的内存。
    CPU是如何访问内存的呢?最简单直接的方式就是物理寻址,也就是CPU直接通过物理地址去访问内存,但物理寻址最大的一个问题就是地址空间缺乏保护:直接暴露物理地址,进程可以访问到任何物理地址,这是非常危险的,故引入了虚拟寻址。虚拟寻址就是CPU通过访问虚拟地址,经过虚拟内存地址到物理内存地址的翻译获得物理地址,才能访问到对应的内存,这个翻译过程由CPU的内存管理单元(MMU)完成。
    虚拟内存
    在虚拟地址到物理地址的翻译过程中可以增加一些权限判定,对地址空间进行保护,操作系统为每个进程提供了一个独立的、私有的、连续的地址空间,这就是虚拟内存。虚拟内存保护了进程的地址空间,使得进程之间互不干扰。
    对于进程而言,它可见的部分只有虚拟内存,但实际上虚拟内存除了映射到物理内存以外,还有可能映射到磁盘,当物理内存的空间不足时,可以将部分内存数据交换到磁盘,也就是内存交换机制,有了该机制后,虚拟内存就可以利用磁盘拓展内存空间。
    [图片]
    应用层面(iOS)的内存管理
    iOS使用虚拟内存机制,但大多数移动设备包括iOS在內使用闪存,不存在内存和磁盘的交换,因此不支持内存交换机制。当内存不够用时,iOS会发出内存警告,didReceiveMemoryWarning方法就是在内存警告时会被触发,此时APP会清理一些不必要的内存来释放一定空间,当释放过后内存还是不够用时,就会发生OOM崩溃。在ios app maximum memory budget上统计了单个APP能够使用的最大内存,以iPhone12Pro为例,总共可用内存为5703MB,单个APP的可用内存达到了3054MB,占比54%,可以看出单个APP要发生OOM崩溃,绝大多数情况都是程序本身出现了问题。因此,合理控制APP的内存是至关重要的事情,应该尽可能的减少内存占用,并对内存警告以及 OOM 崩溃做好防范。
  1. iOS使用虚拟内存机制
  2. 没有内存交换机制
  3. 内存有限,但单个APP可用内存大
  4. 当内存不够用时,会触发内存警告
    Clean Memory & Dirty Memory
    对于一般的操作系统,Clean Memory可以理解为是能够进行Page Out的部分,但是因为iOS不存在内存交换的机制,所以对于iOS来说,Clean Memory指的是能被重新创建的内存,例如未写入数据的内存。
int *array = malloc(200 * sizeof(int));
array[0] = 32
array[199] = 64

例如创建一个数组,只有写入了数据的部分array[0] 和 array[199]才属于Dirty Memory,未写入的部分都属于Clean Memory。Dirty memory会始终占据内存,直到内存不够用时,系统便会开始清理。

在这里插入图片描述

Compressed Memory

当内存不够用时,iOS会压缩部分内存,在需要读写这部分内存的时候再去解压,以达到节约内存的目的,对应的被压缩的内存,就是Compressed Memory。
综上,iOS的内存占用组成还可以如下图所示:
在这里插入图片描述

当可使用的内存达到低位时(比如有很多应用在后台,或者前台应用使用了过多物理内存),操作系统就会试图去减小内存压力,它会做以下几件事:

  1. 首先,系统会移除一些Clean Memroy pages
  2. 如果应用使用了太多的Dirty Memory,系统就会对应用发送警告以期望应用自己去释放一些内存
  3. 如果在数次警告之后,应用程序还是继续使用大量的Dirty Memory,系统就会杀掉这个应用

进程是分配资源的最小单位,每个进程都有独立的虚拟内存地址空间,分配的资源如右图所示。

  • 全局区、常量和代码区有系统自动加载和释放
  • 栈区存放局部变量、临时变量,由编译器自动分配和释放
  • 堆区用于存放进程运行中被动态分配的内存段,由程序员分配和释放(目前iOS基本都使用ARC来管理对象)

在这里插入图片描述

Autorelease Pool

在ARC下,自动释放池会自动创建,在NSAutoreleasePool | Apple Developer Documentation的有关介绍:

AppKit 和 UIKit 框架在事件循环(RunLoop)的每次循环开始时,在主线程创建一个自动释放池,并在每次循环结束时销毁它,在销毁时释放自动释放池中的所有autorelease对象。通常情况下我们不需要手动创建自动释放池,但是如果我们在循环中创建了很多临时的autorelease对象,则手动创建自动释放池来管理这些对象可以很大程度地减少内存峰值。

简单介绍@autoreleasepool的原理:
如下代码,@autoreleasepool的底层是创建了一个__AtAutoreleasePool结构体对象,在构造函数中调用了objc_autoreleasePoolPush()函数,释放结构体时会调用objc_autoreleasePoolPop()函数。

@autoreleasepool {// ...
}struct __AtAutoreleasePool {__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}void * atautoreleasepoolobj;
};/* @autoreleasepool */ 
__AtAutoreleasePool __autoreleasepool; 

进一步看下objc_autoreleasePoolPush()和objc_autoreleasePoolPop()函数的源码,可以看到其实这两个函数时调用了AutoreleasePoolPage的两个方法push()和pop(),所以@autoreleasepool底层就是使用AutoreleasePoolPage类来实现的。

// NSObject.mm
void * objc_autoreleasePoolPush(void)
{return AutoreleasePoolPage::push();
}void objc_autoreleasePoolPop(void *ctxt)
{AutoreleasePoolPage::pop(ctxt);
}

每个线程(包括主线程)都维护自己的NSAutoreleasePool对象栈。新创建的池子会被添加到栈的顶部,销毁池子时,池子会从栈的顶部移除。自动释放的对象会被放入当前线程的顶部自动释放池中。当一个线程终止时,它会自动清空所有与其关联的自动释放池。

因此在程序运行过程中,可能会有多个AutoreleasePoolPage对象

  • 自动释放池与线程一一对应
  • 自动释放池(即所有的AutoreleasePoolPage对象)是以栈为结点通过双向链表的形式组合而成
  • 每个AutoreleasePoolPage对象占用4096字节内存,其中56个字节用来存放内部的成员变量,其余的4040个字节用来存放autoreleasepool对象的地址
    在这里插入图片描述

在MRC下,当我们不需要一个对象时,就调用release或autorelease来释放它

  • release:对象的引用计数立即-1,若-1后对象的引用计数为0,对象就会被销毁
  • autorelease:会将该对象放入自动释放池,交由自动释放池给池中的对象release,因此autorelease相当于延迟了对象的释放
  • 系统干预释放
- (void)viewDidLoad {[super viewDidLoad];    Person *person = [[[Person alloc] init] autorelease];    NSLog(@"%s", __func__);
}- (void)viewWillAppear:(BOOL)animated
{[super viewWillAppear:animated];    NSLog(@"%s", __func__);
}- (void)viewDidAppear:(BOOL)animated
{[super viewDidAppear:animated];    NSLog(@"%s", __func__);
}// -[ViewController viewDidLoad]
// -[ViewController viewWillAppear:]
// -[Person dealloc]
// -[ViewController viewDidAppear:]

对象的dealloc方法不是在viewDidLoad结束后释放,而是viewWillAppear方法结束后释放的,系统干预释放是由RunLoop来控制,会在当前RunLoop每次循环结束时释放,person对象在viewWillAppear方法结束后释放,说明viewDidLoad和viewWillAppear在同一次循环里。

  • 手动干预释放
- (void)viewDidLoad {[super viewDidLoad];    @autoreleasepool {HTPerson *person = [[[HTPerson alloc] init] autorelease];  }  NSLog(@"%s", __func__);
}- (void)viewWillAppear:(BOOL)animated
{[super viewWillAppear:animated];    NSLog(@"%s", __func__);
}- (void)viewDidAppear:(BOOL)animated
{[super viewDidAppear:animated];    NSLog(@"%s", __func__);
}// -[Person dealloc]
// -[ViewController viewDidLoad]
// -[ViewController viewWillAppear:]
// -[ViewController viewDidAppear:]

添加在手动创建的@autoreleasepool中的对象,在@autoreleasepool的大括号结束时就会释放,不受RunLoop的控制。

内存优化

对内存泄漏的处理

内存泄漏指的是应该释放但没有正确释放掉的内存,导致一直占据着内存。

block循环引用

__weak typeof(self) weakSelf = self;
self.block = ^{__strong typeof(weakSelf) strongSelf = weakSelf;  // 防止self被释放NSLog(@"%@",weakSelf.app);
};
self.block();

ReactiveCocoa中潜在的内存泄漏及解决方案

ReactiveCocoa中潜在的内存泄漏及解决方案
原因是RAC强引用

NSTimer

对非OC对象的内存处理

  • ARC模式仅对OC对象进行自动内存管理, 比如 CoreFoundation 框架下的 CI、CG、CF 等开头的类的对象,在使用完毕后仍需我们手动释放

使用@autoreleasepool来减少峰值内存占用

苹果官方文档Using Autorelease Pool Blocks中有通过使用使用@autoreleasepool来减少峰值内存占用的示例代码:

NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {@autoreleasepool {NSError *error;NSString *fileContents = [NSString stringWithContentsOfURL:urlencoding:NSUTF8StringEncoding error:&error];/* Process the string, creating and autoreleasing more objects. */}
}

didReceiveMemoryWarning及时清除Cache

图片/视频的加载、VC的加载可能导致内存暴涨,可以通过监听UIApplicationDidReceiveMemoryWarningNotification或者VC自带的didReceiveMemoryWarning方法在内存警告时及时的清除cache

根据业务场景选择NSCache而非NSDictionary

在这里插入图片描述
场景举例:在收到内存警告时,我们尝试将Dictionary这部分的内容释放掉,但是Dictionary因未使用是Compressed Memory,处于被压缩的状态,解压、释放这部分内容之后,Dictionary处于未压缩状态,可能还会导致内存占用更大了,所以业务可以根据业务的具体场景,在允许的情况下更推荐使用NSCache而非NSDictionary,因为NSCache会在内存警告时由系统自动释放内存。

Memory Graph

通过 Debug Memory Graph 可以查看当前进程中所有生命周期内的对象。我们可以在调试时通过这个功能发现一些本来应该被释放但是却没有被释放的对象,从而确定哪些对象有内存泄漏的嫌疑。

  • Memory Graph可以帮助我们找到循环引用和内存泄漏,正在使用的内存以及每个区域的大小。
  • Memory Graph显示应用程序使用的内存的位置,以及这些使用内存之间的引用关系

Xcode运行App后,点击下图的图标,可以打开memory graph

Target Pointer

Apple在2013年9月推出了iPhone5s,配备了首个采用64位架构的A7双核处理器,为了节省内存和提高执行效率,苹果提出了Tagged Pointer的概念
对于64位程序,引入Tagged Pointer之后,相关逻辑能减少一半的内存占用,以及三倍的访问速度提升,100倍的创建,销毁速度提升。

原有的对象为什么会浪费内存?

  • 以一个NSNumber为例,对象存储在堆上,NSNumber的指针中存储的是堆中NSNumber对象的地址值,
  • 他所占用的内存与cpu的位数有关,在32位系统下占4个字节,在64位系统下占8个字节,、指针类型的大小通常也是与cpu位数相关,一个指针所占用的内存在32位下cpu为4个字节,在64位cpu下也是8个字节
  • 如果没有Taggedpointer对象,NSNumber一类的对象从32位机器迁移到64位机器以后,所占用的内存会翻倍
  • 对象需要在堆上分配内存,同时需要维护引用计数,管理生命周期,程序额外的逻辑造成运行效率上的耗损

Tagged Pointer的引入

  • NSNumber,NSDate,NSString一类的变量本身的值需要占用的内存一半不需要8字节,拿整数来说,4个字节所能表示的数对于绝大多数情况都是可以处理的
  • 因此可以将一个对象的指针拆成两部分,一部分用来直接保存数据,另一部份用来做一个特殊标记,表示这是一个特殊的指针,不指向任何一个地址

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

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

C# CAD SelectionFilter下TypedValue数组

SelectionFilter是用于过滤AutoCAD实体的类&#xff0c;在AutoCAD中&#xff0c;可以使用它来选择具有特定属性的实体。构造SelectionFilter对象时&#xff0c;需要传入一个TypedValue数组&#xff0c;它用于定义选择规则。 在TypedValue数组中&#xff0c;每个元素表示一个选…

vscode 开发代码片段插件

环境准备 node - 20v版本 &#xff0c;推荐使用nvm进行版本控制全局安装 "yo" 是 Yeoman 工具的命令行工具&#xff0c; npm i yo -g全局安装 generator-code 是一个 Yeoman 脚手架 gernerator-code npm i gernerator-code -g全局安装 npm install -g vsce官方文档 …

1.Electron初始与安装

这里写目录标题 一、前言二、下载三、简要总结 一、前言 原文以及该系列后续文章请参考&#xff1a;安装Electron 随着前端的不断强盛&#xff0c;现在的前端已经不再满足于网页开发了&#xff0c;而是在尝试能否使用前端的开发逻辑来开发PC端的桌面软件。 即用html、js、css…

服务器遭受 DDoS 攻击的常见迹象有哪些?

服务器遭受 DDoS 攻击的现象很常见&#xff0c;并且有时不容易预防&#xff0c;有部分原因是它们的形式多种多样&#xff0c;而且黑客手段越来越隐蔽。如果您怀疑自己可能遭受 DDoS 攻击&#xff0c;可以寻找多种迹象。以下是 DDoS 攻击的5个常见迹象&#xff1a; 1.网络流量无…

全视通智慧社区居家养老解决方案如何让老人住的更舒心?

随着老龄化社会的加速发展&#xff0c;老年人的养老问题愈发受到社会关注。传统的养老方式已经无法满足现代老年人的需求&#xff0c;他们更加注重生活的品质和舒适度。为了响应《城市居家适老化改造指导手册》要求&#xff0c;全视通智慧社区&居家养老解决方案应运而生&am…

人工智能技术应用笔记(二):OpenAI SORA文生视频模型技术报告全文中英对照 (GPT4翻译+人工润色)

目录 Video generation models as world simulators&#xff08;视频生成模型作为世界模拟器&#xff09; Turning visual data into patches &#xff08;将视觉数据转换为图像块&#xff09; Video compression network &#xff08;视频压缩网络&#xff09; Spacetim…

JMeter 测试脚本编写技巧

是一款开源软件&#xff0c;用于进行负载测试、性能测试及功能测试。测试人员可以使用 JMeter 编写测试脚本&#xff0c;模拟多种不同的负载情况&#xff0c;从而评估系统的性能和稳定性。以下是编写 JMeter 测试脚本的步骤。 第 1 步&#xff1a;创建测试计划 在JMeter中&am…

【前端工程化面试题目】webpack 的热更新原理

可以在顺便学习一下 vite 的热更新原理&#xff0c;请参考这篇文章。 首先有几个知识点需要明确 热更新是针对开发过程中的开发服务器的&#xff0c;也就是 webpack-dev-serverwebpack 的热更新不需要额外的插件&#xff0c;但是需要在配置文件中 devServer 属性中配置 hot&a…

【学习iOS高质量开发】——接口与API设计

文章目录 一、用前缀避免命名空间冲突1.为什么用前缀避免明明冲突2.应当如何避免3.要点 二、提供“全能初始化方法”1.什么是全能初始化方法2.如何重写初始化方法3.一个类有多个全能初始化方法要注意的问题3.要点 三、实现description方法1.什么是description方法2.在descripti…

语言与科技创新(大语言模型对科技创新的影响)

1.语言因素对科技创新的影响 科技创新中的语言因素至关重要&#xff0c;具体体现在以下几个方面&#xff1a; 科技文献交流&#xff1a; 英语作为全球科学研究的通用语言&#xff0c;极大地推动了科技成果的国际传播与合作。在国际上&#xff0c;科学家们在发表论文、报告研究…

.NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库

一、效果 记录日志为文档 记录日志到数据库 二、添加NuGet包 三、log4net.config代码配置 <?xml version"1.0" encoding"utf-8" ?> <log4net><!-- Debug日志 --><appender name"RollingFileDebug" type"log4net…

三防平板丨平板终端丨三防平板电脑丨建筑工地应用

随着建筑工程越来越复杂和规模越来越大&#xff0c;工地管理和协调变得越来越复杂。在这个过程中&#xff0c;工业设备的作用越来越重要&#xff0c;而三防平板作为一种实用的工业设备&#xff0c;在工地上的应用越来越广泛。本文将介绍三防平板在工地使用中的优势和应用。 一…

[AudioRecorder]iPhone苹果通话录音汉化破解版-使用巨魔安装-ios17绕道目前还不支持

首先你必须有巨魔才能使用&#xff01;&#xff01; 不会安装的&#xff0c;还没安装的移步这里&#xff0c;ios17 以上目前装不了&#xff0c;别看了&#xff1a;永久签名 | 网址分类目录 | 路灯iOS导航-苹果签名实用知识网址导航-各种iOS技巧-后厂村路灯 视频教程 【Audio…

STM32Cubemx TB6612直流电机驱动

一、TB6612FNG TB6612是一个支持双电机的驱动模块&#xff0c;支持PWM调速。PWMA、AIN1、AIN2 为一组控制引脚&#xff0c;PWMA 为 PWM 速度控制引脚&#xff0c;AIN1、AIN2 为方向控制引脚&#xff1b;PWMB、BIN1、BIN2 为一组控制引脚&#xff0c;PWMB 为 PWM 速度控制引脚&…

PPT导出PDF时保持图像高清的方法

问题: 我们经常会发现&#xff0c;在PPT中插入的图片非常高清&#xff0c;但是通过PPT转换为PDF之后&#xff0c;图片就会出现不同程度的失真。 问题产生的原因: 这是因为Acrobat的PDF Maker在将PPT转换为PDF的时候&#xff0c;对PPT中的图片进行了压缩 Solution: 在PPT的…

单片机项目调试中的技巧和常见问题解决

单片机是嵌入式系统中的重要组成部分&#xff0c;在各种电子设备中发挥着重要的作用。在单片机项目开发过程中&#xff0c;调试是至关重要的一环&#xff0c;同时也会遇到一些常见问题。本文将介绍一些单片机项目调试的技巧以及常见问题的解决方法&#xff0c;希望能够对单片机…

NLP_BERT与GPT争锋

文章目录 介绍小结 介绍 在开始训练GPT之前&#xff0c;我们先比较一下BERT和 GPT 这两种基于 Transformer 的预训练模型结构&#xff0c;找出它们的异同。 Transformer架构被提出后不久&#xff0c;一大批基于这个架构的预训练模型就如雨后春笋般地出现了。其中最重要、影响…

【天衍系列 01】深入理解Flink的 FileSource 组件:实现大规模数据文件处理

文章目录 01 基本概念02 工作原理03 数据流实现04 项目实战4.1 项目结构4.2 maven依赖4.3 StreamFormat读取文件数据4.4 BulkFormat读取文件数据4.5 使用小结 05 数据源比较06 总结 01 基本概念 Apache Flink 是一个流式处理框架&#xff0c;被广泛应用于大数据领域的实时数据…

JVS智能BI的ETL数据集实践:数据自动化分析的秘诀

数据集是JVS-智能BI中承载数据、使用数据、管理数据的基础&#xff0c;同样也是构建数据分析的基础。可以通俗地将其理解为数据库中的普通的表&#xff0c;它来源于智能的ETL数据加工工具&#xff0c;可以将数据集进行分析图表、统计报表、数字大屏、数据服务等制作。 数据集管…
推荐文章