Systrace学习笔记

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.rhkb.cn/news/161398.html

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

相关文章

OpenAI开放gpt-3.5turbo微调fine-tuning测试教程

文章目录 openai微调 fine-tuning介绍openai微调地址jsonl格式数据集准备点击上传文件 openai微调 fine-tuning介绍 openai微调地址 网址:https://platform.openai.com/finetune jsonl格式数据集准备 使用Chinese-medical-dialogue-data数据集git clone进行下载 …

Puppeteer记录操作过程及优秀的开源插件(五)

Puppeteer记录操作过程及优秀的开源插件(五) Puppeteer记录操作过程及优秀的开源插件(五)一、简介二、自动生成测试代码三、优秀的开源插件四、参考案例 一、简介 本节我们将介绍通过浏览器工具记录用户的实际操作,并…

Java基础之接口(interface)详解

对Java核心技术卷的一个简单笔记 目录 前言1.接口的概念2.接口的声明格式3.接口的属性4.接口和抽象类的区别5.继承和接口混合使用的一些规则6.继承父类和实现接口时的一些同名冲突问题6.1方法名冲突6 .2常量名冲突 前言 总结一下基础阶段接口常见的问题 1.接口的概念 接口 &…

F. Minimum Maximum Distance Codeforces Round 903 (Div. 3)

Problem - F - Codeforces 题目大意&#xff1a;有一棵n个点的树&#xff0c;其中有k个标记点&#xff0c;令点i到所有标记点的最远距离为fi&#xff0c;问所有点中fi的最小值是多少 1<k<n<2e5 思路&#xff1a;我们首先考虑取得最小值的点在哪&#xff0c;我们假设…

Unity教程 ECS 内存分配器原理详解

一、UnityECS内存分配器的作用 在传统的面向对象编程模式中&#xff0c;我们通常使用堆内存来存储实体和组件数据。然而&#xff0c;由于实体和组件数据的规模通常非常庞大&#xff0c;使用堆内存进行分配和管理会导致内存碎片化和性能下降的问题。为了解决这个问题&#xff0…

常见的数据结构及应用

文章目录 前言数据结构介绍数组链表队列和栈树堆 总结 前言 数据结构是计算机存储、组织数据的方式。在工作中&#xff0c;我们通常会直接使用已经封装好的集合API&#xff0c;这样可以更高效地完成任务。但是作为一名程序员&#xff0c;掌握数据结构是非常重要的&#xff0c;…

MySQL——六、库表操作(下篇)

MySQL 一、INSERT语句二、REPLACE语句三、UPDATE语句四、delete和TRUNCATE语句五、MySQL用户授权1、密码策略2、用户授权和撤销授权 一、INSERT语句 #在表里面插入数据&#xff1a;默认情况下&#xff0c;一次插入操作只插入一行 方式1&#xff1a; INSERT [INTO] 表名 [(colu…

新一代开源语音库CoQui TTS冲到了GitHub 20.5k Star

Coqui TTS 项目介绍 Coqui 文本转语音&#xff08;Text-to-Speech&#xff0c;TTS&#xff09;是新一代基于深度学习的低资源零样本文本转语音模型&#xff0c;具有合成多种语言语音的能力。该模型能够利用共同学习技术&#xff0c;从各语言的训练资料集转换知识&#xff0c;来…

vue2 解密图片地址(url)-使用blob文件-打开png格式图片

一、背景 开发中需要对加密文件进行解码&#xff0c;如图片等静态资源。 根据后端给到的url地址&#xff0c;返回的是图片文件&#xff0c;但是乱码的&#xff0c;需要解码成png图片进行展示 二、请求接口 将后端返回的文件转为文件流&#xff0c;创建Blob对象来存储二进制…

设计模式:工厂方法模式(C#、JAVA、JavaScript、C++、Python、Go、PHP):

本节主要介绍设计模式中的工厂方法模式。 简介&#xff1a; 工厂方法模式&#xff0c;它是对简单工厂模式的进一步抽象化&#xff0c;其好处是可以使系统在不修改原来代码的情况下引进新的产品&#xff0c;即满足开闭原则。 它定义了一个用于创建对象的工厂接口&#xff0c;让…

游游的字母串 (环形数组两点之间的位置)

题目链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 样例&#xff1a; 输入 yab 输出 3 思路&#xff1a; 暴力枚举&#xff0c;全部变成对应的26个字母字符需要的操作步数&#xff0c;取最少的一个操作步数&#xff0c; 这里的操作步数&#xff0…

laravel中锁以及事务的简单使用

一、首先来说一下什么是共享锁&#xff1f;什么是排他锁&#xff1f; 共享&#xff1a;我可以读 写 加锁 , 别人可以 读 加锁。 排他&#xff1a;只有我 才 可以 读 写 加锁 , 也就是说&#xff0c;必须要等我提交事务&#xff0c;其他的才可以操作。 二、简单例子实现加锁 锁…

tomcat 服务器

tomcat 服务器 tomcat: 是一个开源的web应用服务器。区别nginx&#xff0c;nginx主要处理静态页面&#xff0c;那么动态请求&#xff08;连接数据库&#xff0c;动态页面&#xff09;并不是nginx的长处&#xff0c;动态的请求会交给tomcat进行处理。 nginx-----转发动态请求-…

PCL 坡度滤波算法地面分割(C++详细过程版)

目录 一、算法原理1、实现流程2、参考文献二、代码实现三、结果展示一、算法原理 1、实现流程 1、格网示意图 2、计算格网行列数 公式中的特殊符号为向上取整,

Cesium Vue(三)— 相机配置

1. 坐标系转换 1.1 cesium使用到的坐标系 屏幕坐标系&#xff0c;二维的笛卡尔坐标系&#xff0c;API > Cartesian2地理空间坐标系&#xff0c;WGS-84坐标系&#xff0c; API > Cartographic(经度&#xff0c;维度&#xff0c;高度)三维笛卡尔空间直角坐标系&#xff0…

GPT4 Advanced data analysis Code Interpreter 做行业数据分析、可视化处理图像、视频、音频等

1. 跨境电商如何用ChatGPT选品 ChatGPT Jungle scout 案例&#xff1a;跨境电商如何用ChatGFT选品 ChatGPTJungle scout 素材和资料来自&#xff1a; Jungle ScoutEM, Michael Soltis 和 文韬武韬AIGC 1.1 从Jungle scout上下载数据 Date Range > Last 90 days Downlo…

python+大数据校园卡数据分析 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于yolov5的深度学习车牌识别系统实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;3分 该项目较为新颖&am…

Stable Diffusion绘画,卡通,教室

1 girl, parted lips, blush, makeup, light smile, school uniform, classroom, light rays, glow, thighs, collarbone, narrow waist, (masterpiece), wallpaper 1个女孩&#xff0c;双唇&#xff0c;腮红&#xff0c;化妆&#xff0c;浅笑&#xff0c;校服&#xff0c;教室…

基于SSM框架的安全教育平台

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

【Eclipse】设置自动提示

前言&#xff1a; eclipse默认有个快捷键&#xff1a;alt /就可以弹出自动提示&#xff0c;但是这样也太麻烦啦&#xff01;每次都需要手动按这个快捷键&#xff0c;下面给大家介绍的是&#xff1a;如何设置敲的过程中就会出现自动提示的教程&#xff01; 先按路线找到需要的页…