Systrace学习笔记

news2025/3/14 0:23:14

Systrace学习笔记

  • 1.Systrace快捷键
  • 2.线程状态
  • 3.CPU info
  • 4.图形化
    • 4.1 Frames帧
    • 4.2 用户活动
    • 4.3 CPU活动
    • 4.4 系统事件
  • 5. SystemServer
    • 5.1 SystemServer简介
    • 5.2 窗口动画
    • 5.3 AMS(ActivityManagerService)
    • 5.4 WMS(WindowMagerService)
    • 5.5 ServiceThread
    • 5.6 HandlerThread
  • 6. SurfaceFlinger
    • 6.1 App --> BufferQueue
    • 6.2 BufferQueue --> Surface Flinger
    • 6.3Surface Flinger --> HWC
  • 7.Input
    • 7.1 Input流程
    • 7.2 iq、oq、wq
  • 8. VSync信号
    • 8.1 起源
    • 8.2 VSync是什么?
    • 8.3 App绘制到屏幕显示流程
    • 8.4 SurfaceFlinger 、App、 HWC

使用Systrace前提:

  1. Python 2.7.x 环境;
  2. 安卓SDK : systrace 命令在 Android SDK 工具软件包中提供,并且可以在 android-sdk/platform-tools/systrace/ 中找到(旧版带systrace.py)
  3. chrome://tracing/ :浏览器打开systrace.html

Systrace 适用于 Android 4.3(API 级别 18)及更高版本的所有平台版本,但建议将 Perfetto 用于运行 Android 10 及更高版本的设备

1.Systrace快捷键

W:放大
S:缩小
A:左移
D:右移
M:高亮
1 :将当前正在使用中的选择模型更改为“选择”模式。
2 :将当前正在使用中的选择模型更改为“平移”模式。
3 :将当前正在使用中的选择模型更改为“缩放”模式。
4 :将当前正在使用中的选择模型更改为“计时”模式。
G :在当前所选任务的开头显示网格。
左键:在当前选定的时间轴上选择上一个事件。
右键:在当前选定的时间轴上选择下一个事件。

2.线程状态

  • 绿色 Running:线程正在完成与某个进程相关的工作或正在响应中断
  • 蓝色 Runnable:可以运行,等待CPU调度,同一时刻可能有多个线程处于Runnable,这些线程的 task_struct 结构被放入对应 cpu 的Runnable队列中(一个线程最多只能出现在一个 cpu 的可执行队列中)。调度器的任务就是从各个 cpu 的Runnable队列中分别选择一个线程在该cpu 上运行
  • 白色 Sleep:线程没有可执行的任务,可能是因为线程在遇到互斥锁定时被阻塞
  • 橙色 Uninterruptible Sleep - IO Block:线程在遇到 I/O 操作时被阻止或正在等待磁盘操作完成,IO操作慢
  • 紫色 Uninterruptible Sleep:线程在另一内核操作时被阻塞,一般是陷入内核态(内存管理)

3.CPU info

CPU按照核心数和架构分类:
1.非大小核架构:八核/四核/两核同构,频率相同,功耗相同
2.大小核架构:小核主频低功耗低,大核主频高功耗高
八核心:CPU0-3是小核心,CPU4-7是大核心
ohter:4小核心+2大核心;6小核心+2大核心
3. 大中小核架构:大核心1~2个,主频功耗高,用来处理繁重高负载任务

绑核
将任务绑定到一个或一组核心上运行来满足实际需求
负载高-------------------大核心组
任务避免频繁切换----绑定某一个核心
任务要求低-------------绑定小核心组

4.图形化

横坐标是以时间为单位,纵坐标是以进程-线程的方式来划分,同一进程的线程为一组放在一起,可收缩/展开,如下图:

4.1 Frames帧

在每个app进程,都有一个Frames行,正常情况以绿色的圆点表示。当圆点颜色为黄色或者红色时,意味着这一帧超过16.6ms(即发现丢帧),这时需要通过放大这一帧进一步分析问题。

对于Android 5.0(API level 21)或者更高的设备,该问题主要聚焦在UI Thread和Render Thread这两个线程当中。对于更早的版本,则所有工作在UI Thread。

在这里插入图片描述

4.2 用户活动

在这里插入图片描述

4.3 CPU活动

在这里插入图片描述

4.4 系统事件

描绘 SurfaceFlinger 进程(包括 VSync 事件和界面线程交换工作)的其他直方图
在这里插入图片描述

5. SystemServer

5.1 SystemServer简介

Android系统在启动的时候有两个重要的进程:Zygote进程 和 由zygote进程fork出来的system_server进程

system_server 进程主要是用于创建系统服务,AMS、WMS、PMS 都是由它创建的。 具体来说,SystemServer 进程被创建后,主要做了以下工作:

  • 启动 Binder 线程池,这样就可以与其他进程进行通信;
  • 创建 SystemServiceManager,用于对系统服务进行创建、启动和生命周期管理;
  • 启动各种系统服务;

SystemServer进程的核心是SystemServer类,它是Android系统启动后的第一个Java进程。SystemServer类负责启动系统的各种服务,它通过Binder机制提供各种服务接口

SystemServer 由于提供大量的基础服务,所以进程间的通信非常繁忙,且大部分通信都是通过 Binder

public final class SystemServer {
    private static final String TAG = "SystemServer";
    private static final boolean DEBUG_LISTENER = false;
    private static final boolean DEBUG_PRIORITY = false;
    private static final String ANSI_RED_BACKGROUND = "\u001B[31;40m";
    private static final String ANSI_RESET = "\u001B[0m";
    ...
    public static void main(String[] args) {
        ...
        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitBeforeStartServices");
        SystemServer systemServer = null;
        try {
            //创建systemServer实例
            systemServer = new SystemServer();
            //启动系统服务
            systemServer.run();
        } catch (Throwable ex) {
            Log.e("System", "******************************************");
            Log.e("System", "************ Failure starting system services", ex);
            System.exit(10);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }

    //启动各种系统服务的方法
    private void run() {
        ...
        startCoreServices();
        startOtherServices();
        startBootstrapServices();
        ...
    }

    //启动核心服务的方法
    private void startCoreServices() {
        ...
	    //启动属性服务
	    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitializeSystemProperties");
	    SystemProperties.init();
	    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	
	    //启动电源服务
	    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartPowerManagerService");
	    power = powerManagerService;
	    powerManagerService.setPolicy((WindowManagerPolicy) policy);
	    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	
	    //启动USB服务
	    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartUsbService");
	    UsbService usb = new UsbService(context);
	    ServiceManager.addService(Context.USB_SERVICE, usb);
	    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	
	    //启动Vibrator服务
	    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartVibratorService");
	    vibrator = new VibratorService(context);
	    ServiceManager.addService(Context.VIBRATOR_SERVICE, vibrator);
	    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	
	    //启动下载服务
	    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartDownloadService");
	    ServiceManager.addService(Context.DOWNLOAD_SERVICE, new DownloadManagerService(context));
	    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	    ...
    }

    //启动其他服务的方法
    private void startOtherServices() {
        ...
        //启动媒体服务
	    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartMediaServer");
	    media = new MediaServer(context);
	    ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, media.getMediaRouter());
	    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	
	    //启动网络服务
	    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartNetworkManagementService");
	    try {
	        final NetworkManagementService nmService = NetworkManagementService.create(context);
	        ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, nmService);
	    } catch (Throwable e) {
	        reportWtf("starting NetworkManagementService", e);
	    }
	    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	
	    //启动位置服务
	    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartLocationManagerService");
	    locationManagerService = new LocationManagerService(context);
	    ServiceManager.addService(Context.LOCATION_SERVICE, locationManagerService);
	    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	    ...
    }

    //启动引导服务的方法
    private void startBootstrapServices() {
        //重命名文件系统
	    if (!mRuntimeRestart) {
	        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "RenameFilesystem");
	        ZygoteInit.renameAndRemoveOldUserSystemDirs();
	        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
	    }
	
	    //格式化data分区
	    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartBootstrapServices");
	    Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
	    intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
	    intent.setPackage("android");
	    context.sendBroadcastAsUser(intent, UserHandle.ALL);
	    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
    }
    ...
}

5.2 窗口动画

应用启动流程:点击App时,首先Launcher会启动一个StartingWindow,等App中启动页面的第一帧绘制好了,就会马上从Launcher切换回App的窗口动画。

Android 9.0之前App启动动画在SystemServer里
Android 9.0之后App启动动画由Laucher和App自身第一帧组成

5.3 AMS(ActivityManagerService)

AMS主要负责Android系统中四大组件的启动、切换、调度以及应用进程管理和调度工作

AMS 相关的 Trace 一般会用 TRACE_TAG_ACTIVITY_MANAGER 这个 TAG,在 Systrace 中的名字是 ActivityManager。

5.4 WMS(WindowMagerService)

WMS管理所有的窗口,包括创建、删除、修改,以及将某个窗口设置为焦点窗口。

一般会用 TRACE_TAG_WINDOW_MANAGER 这个 TAG,在 Systrace 中 WindowManagerService 在 SystemServer 中多在 对应的 Binder 中出现。

5.5 ServiceThread

ServiceThread 继承自 HandlerThread。

UIThread、IoThread、DisplayThread、AnimationThread、FgThread、SurfaceAnimationThread都是继承自 ServiceThread,分别实现不同的功能,根据线程功能不同,其线程优先级也不同。

每个 Thread 都有自己的 Looper 、Thread 和 MessageQueue,互相不会影响。Android 系统根据功能,会使用不同的 Thread 来完成。

5.6 HandlerThread

BackgroundThread,许多对性能没有要求的任务,一般都会放到 BackgroundThread 中去执行。

6. SurfaceFlinger

SurfaceFlinger始终显示内容,始终保留一个缓冲区。

作用:接收所有缓冲区,进行合成,发送到显示设备(屏幕)

触发:收到VSync信号后,开始以帧的形式绘图;

流程:收到VSync信号后,SurfaceFlinger遍历层列表,寻找新缓冲区,找到新的缓冲区就获取,未找到新的就使用以前的缓冲区,某个层上没有提交缓冲区就会忽略该层,收集完后询问HWC如何合成

6.1 App --> BufferQueue

App与BufferQueue交互流程:收到vsync信号后,应用主线程(UI Thread)被唤醒,主线程处理完数据后,会唤醒应用渲染线程RenderThread同步数据,RenderThread会从BufferQueue取出一个Buffer,然后往Buffer写入具体的 drawcall,完成后再将有数据的Buffer还给BufferQueue。

6.2 BufferQueue --> Surface Flinger

思考后认为,App是不断往BufferQueue里面丢数据的,而vsync信号的发送与前面无关,就是系统提醒Surface Flinger可以画图了,那Surface Flinger就马上去BufferQueue取数据,然后画图。

6.3Surface Flinger --> HWC

HWC HAL是用于合成从Surfaceflinger接收到的图层,而分担GLES和GPU执行合成的压力,提升整体性能和效率

使用HWC来合成该窗口而不是用surfaceflinger通过GPU来合成原因?
1)大部分GPU没有为合成优化
2)当使用Surfaceflinger通过GPU来合成layers 时,应用是无法用GPU来做渲染的工作的

7.Input

Input分类

  • 触摸事件(Down、Up、Move)
  • Key 事件(Home Key 、 Back Key)

7.1 Input流程

  1. system_server的native线程InputReader首先负责从EventHub中监听并从屏幕驱动读取上报的触控事件,然后放入InboundQueue(iq)中,然后唤醒另外一条native线程InputDispatcher负责进行进一步事件分发(对事件进行包装后)
  2. InputDispatcher 在拿到 InboundQueue(iq)中的事件之后, 对注册了Input事件的所有App:
    a. 派发到各个App连接的OutboundQueue(oq)
    b.记录到各个App的WaitQueue(wq)
  3. App 接收到 Input 事件,InputDispatcher通过直接唤醒、Binder方式将主线程UI Thread唤醒,同时记录到 PendingInputEventQueue ,然后对事件进行分发处理
  4. App 处理完成后,回调 InputManagerService 将负责监听的 WaitQueue 中对应的 Input 移除

7.2 iq、oq、wq

  • InboundQueue(iq)
    InputDispatcher 执行 notifyKey 的时候,会将 Input 事件封装后放到 InboundQueue 中,后续 InputDispatcher 循环处理 Input 事件的时候,就是从 InboundQueue 取出事件然后做处理
  • Outbound(oq)
    OutboundQueue 指的是要被 App 拿去处理的事件队列,每一个 App(Connection) 都对应有一个 OutboundQueue ,事件会先进入 InboundQueue ,然后被 InputDIspatcher 派发到各个 App 的 OutboundQueue
  • WaitQueue (wq)
    • WaitQueue(wq) 里面记录的是已经派发给 App 但是 AppConnection 还在处理没有返回处理成功的事件
    • 当 InputDispatcher 将 Input 事件分发出去之后,将 DispatchEntry 从 outboundQueue 中取出来放到 WaitQueue 中,当 publish 出去的事件被处理完成(finished),InputManagerService 就会从应用中得到一个回复,此时就会取出 WaitQueue 中的事件,从 Systrace 中看就是对应 App 的 WaitQueue 减少

8. VSync信号

8.1 起源

显示屏上一帧画面的显示过程,是像素自上而下逐行扫描的过程,如果在上一帧的扫描还没有结束的情况下,屏幕又开始扫描下一帧的像素,那么就会出现下面描绘撕裂(撕裂)的情况。

这个问题最初是在PC上被重视和解决的,GPU厂商开发出了一种防止屏幕撕裂的技术方案,全称垂直同步(中文名垂直同步,简称VSync)。思路就是在屏幕刷新之前基本向外提供一个信号,主机端根据此信号选择合适的策略完成屏幕的刷新,避免数据刷新和屏幕扫描不匹配(撕裂)的情况发生。

8.2 VSync是什么?

Vsync是信号,用来控制App渲染图像、SurfaceFlinger合成图像的节奏。Vsync可以由硬件或软件产生,主要是由硬件HWC生成。

HWC 可生成 VSYNC 事件并通过回调将事件发送到 SurfaceFlinge , DispSync 将 Vsync 生成 Choreographer 使用的 VSYNC_APP 和 SurfaceFlinger 使用的 VSYNC_SF 信号.

8.3 App绘制到屏幕显示流程

  1. App 在收到 Vsync-App 的时候,在主线程进行 measure、layout、draw(构建 DisplayList , 里面包含 OpenGL 渲染需要的命令及数据) 。这里对应的 Systrace 中的主线程 doFrame 操作
  2. CPU 将数据上传(共享或者拷贝)给 GPU, 这里 ARM 设备 内存一般是 GPU 和 CPU 共享内存。这里对应的 Systrace 中的渲染线程的 flush drawing commands 操作
  3. 通知 GPU 渲染,真机一般不会阻塞等待 GPU 渲染结束,CPU 通知结束后就返回继续执行其他任务,使用 Fence 机制辅助 GPU CPU 进行同步操作;
  4. swapBuffers,并通知 SurfaceFlinger 图层合成。这里对应的 Systrace 中的渲染线程的 eglSwapBuffersWithDamageKHR 操作
  5. SurfaceFlinger 开始合成图层,如果之前提交的 GPU 渲染任务没结束,则等待 GPU 渲染完成,再合成(Fence 机制),合成依然是依赖 GPU,不过这就是下一个任务了.这里对应的 Systrace 中的 SurfaceFlinger 主线程的 onMessageReceived 操作(包括 handleTransaction、handleMessageInvalidate、handleMessageRefresh)SurfaceFlinger 在合成的时候,会将一些合成工作委托给 Hardware Composer,从而降低来自 OpenGL 和 GPU 的负载,只有 Hardware Composer 无法处理的图层,或者指定用 OpenGL 处理的图层,其他的 图层偶会使用 Hardware Composer 进行合成
  6. 最终合成好的数据放到屏幕对应的 Frame Buffer 中,固定刷新的时候就可以看到了

8.4 SurfaceFlinger 、App、 HWC

  1. HWC产生第一个VSync信号,SF和App同时收到信号
  2. SF收到VSync-sf信号,开始进行App上一帧的Buffer的合成
  3. App收到VSync-app信号后,开始进行这一帧的Buffer的渲染(第1,2,3,4步)
  4. HWC产生第二个VSync信号,SF和App同时收到信号,SF获取App在第2步中渲染的Buffer,开始合成(第5步);App收到VSync-app信号,开始新一帧的Buffer渲染(第1,2,3,4步)

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

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

相关文章

软考-网络安全体系与网络安全模型

本文为作者学习文章,按作者习惯写成,如有错误或需要追加内容请留言(不喜勿喷) 本文为追加文章,后期慢慢追加 by 2023年10月 网络安全体系相关安全模型 BLP机密性模型 BLP(Biba-格雷泽-麦克拉伦&#x…

安装Elasticsearch步骤(包含遇到的问题及解决方案)

注:笔者是在centos云服务器环境下安装的Elasticsearch 目录 1.安装前准备 2.下载Elasticsearch 3.启动Elasticsearch 非常容易出问题 第一次运行时,可能出现如下错误: 一、内存不足原因启动失败 二、使用root用户启动问题 三、启动ES自…

【数据仓库】hadoop生态圈与数据仓库

文章目录 1.大数据定义2. Hadoop与数据仓库3. 关系数据库的可扩展性瓶颈4. CAP理论5. Hadoop数据仓库工具5.1. RDS和TDS5.2. 抽取过程5.3. 转换与装载过程5.4. 过程管理和自动化调度5.5.数据目录(或者称为元数据管理)5.6.查询引擎…

ELK + Filebeat 分布式日志管理平台部署

ELK Filebeat 分布式日志管理平台部署 1、前言1.1日志分析的作用1.2需要收集的日志1.3完整日志系统的基本特征 2、ELK概述2.1ELK简介2.2为什么要用ELK?2.3ELK的组件 3、ELK组件详解3.1Logstash3.1.1简介3.1.2Logstash命令常用选项3.1.3Logstash 的输入和输出流3.1.4Logstash配…

Tengine 边缘AI计算框架移植RV1126(包括opencv的交叉编译)

目录 1.编译opencv 2.拷贝SDK源码到虚拟机 3. 拉取TIM-VX代码 4.拉取Tengine源码并配置 1.编译opencv 编译opencv是为了,在编译Tengine时指定OpenCVConfig.cmake,以便寻找特定的opencv动态库 01.从github拉取opencv源代码 git clone -b 4.5.5 https://github.co…

unity 浏览器插件【embedded browser(原zfbrowser)】简单教程,使unity支持web h5页面,附软件下载链接

一 简介 这是个在项目中使用了很久的浏览器插件。 很负责任的说这是在pc平台上最好用的浏览器插件 商业付费价格78刀,相比3d webview等插件动不动就178、368的价格就显得很良心 最新版下载链接(请勿商用) 1.1 功能概述 基本和普通浏览器无…

基于Scrapyd与Gerapy部署scrapy爬虫方案【可用于分布式爬虫部署】

scrapyd部署爬虫 Scrapyd 是一个基于 Scrapy 的开源项目,它提供了一个简单的方式来部署、运行和监控 Scrapy 爬虫。它是一个用于集成 Scrapy 爬虫到分布式架构中的工具,允许您在分布式环境中运行爬虫,并提供了一组 Web API,用于管…

软考高级系统架构设计师系列之:数学与经济管理

软考高级系统架构设计师系列之:数学与经济管理 一、数学与经济管理二、图论应用-最小生成树三、图论应用-最短路径四、图论应用-网络与最大流量五、运筹方法-线性规划六、运筹方法-动态规划七、运筹方法-转移矩阵八、运筹方法-排队论九、运筹方法-决策-不确定决策十、运筹方法…

携手北大医学部、哈佛BCH顶尖平台,飞鹤全面启动脑发育战略

10月17日,“专研大脑营养 聪明中国宝宝”飞鹤脑发育战略发布会在北京举办。会上,中国飞鹤宣布启动脑发育战略。诺奖得主迈克尔莱维特、中国工程院院士朱蓓薇、中国工程院院士陈卫、北京大学神经科学研究所副所长邢国刚等海内外专家齐聚,共同探…

Redis数据结构之listpack

前言 当数据量较小时,Redis 会优先考虑用 ziplist 来存储 hash、list、zset,这么做可以有效的节省内存空间,因为 ziplist 是一块连续的内存空间,它采用一种紧凑的方式来存储元素。但是它也有缺点,比如查找的时间复杂度…

Unity2023, Unity2022, Unity2021的性能对比(帧率)

最近由于需要用到Unity最新版的一些功能,比如Spline,比如Foward渲染,新项目用了Unity2022.3.5版本,但是出包之后,感觉帧率很低。本着好奇的态度,专门写了一个测试场景,分别在Unity2023.1.15&…

激光跟踪仪在风电行业中的应用

随着全球能源行业重点从化石能源向可再生能源转移,风电行业逐渐成为我国能源供应体系的重要分支,相关的风电检测设备需求量急剧增加。 风电设备主要特点是“重、大”,在过去,主要使用大型卡尺、两点式仪表、专用模板等量具对重要尺…

PS运行中缺失d3dcompiler_47.dll问题的5个有效修复方法总结

在使用ps作图的时候,我们有时会遇到一些问题,其中之一就是“PS运行中缺失d3dcompiler_47.dll”的问题。这个问题可能会导致PS无法正常运行,“d3dcompiler_47.dll”。这是一个动态链接库文件,它是DirectX的一部分,主要负…

Docker仓库harbor私服搭建

Harbor和Registry都是Docker的镜像仓库,但是Harbor作为更多企业的选择,是因为相比较于Regisrty来说,它具有很多的优势。 提供分层传输机制,优化网络传输 Docker镜像是是分层的,而如果每次传输都使用全量文件(所以用FT…

Kubernetes 基础

Kubernetes是什么 K8S由google的Borg系统(博格系统,google内部使用的大规模容器编排工具)作为原型, 后经GO语言延用Borg的思路重写并捐献给CNCF基金会开源。 云原生基金会(CNCF)于2015年12月成立,隶属于Linux基金会…

Lock锁的使用方法(一)

public class LockTest01 {private Lock lock new ReentrantLock();public static void main(String[] args) throws InterruptedException {/*** Lock锁 获取锁和释放锁 需要开发人员自己定义*/LockTest01 lockTest01 new LockTest01();lockTest01.print();Thread.sleep(500…

C++基础入门详解(二)

文章目录 引用语法和使用场景基本语法使用场景引用作函数参数引用作返回值常引用 权限问题权限的放大、平移、缩小类型转化时使用的 const 引用的底层逻辑 内联函数内联函数缺点 引用 C中的引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器…

海量小文件数据传输如何确保安全性

在当今的信息化社会,企业需要处理和传输的文件越来越多,越来越大。其中,海量小文件数据是一种特殊的数据类型,它由数亿级别的小文件(通常小于1MB)组成,它在图片网站、物联网设备、日志分析等场景…

尚硅谷Flink(完)FlinkSQL

🧙FlinkSQL🏂🤺 Table API 和 SQL 是最上层的 API,在 Flink 中这两种 API 被集成在一起,SQL 执行的对象也是Flink 中的表(Table),所以我们一般会认为它们是一体的。 SQL API 是基于…

C#的数据集:DataSet对象

目录 一、合并DataSet内容 1.源码 2.生成效果 二、 复制DataSet内容 1.源码 2.生成效果 DataSet对象就像存放于内存中的一个小型数据库。它可以包含数据表、数据列、数据行、视图、约束以及关系。通常,DataSet的数据来源于数据库或者XML,为了从数…