京东金融Android瘦身探索与实践

news2024/9/23 9:28:08

作者:京东科技 冯建华

一、背景

随着业务不断迭代更新,App的大小也在快速增加,2019年~2022年期间一度超过了117M,期间我们也做了部分优化如图1红色部分所示,但在做优化的同时面临着新的增量代码,包体积一直持续上升**。**包体积直接或间接地影响着下载转化率、安装时间、磁盘空间等重要指标,所以投入精力发掘更深层次的安装包体积优化是十分必要的。根据谷歌商店的内部数据,APK体积每减少10M,平均可增加~1.5%的下载转化率,如图2所示:

图1 京东金融Android版本2019-2022体积变化过程 (红色部分是期间做的部分优化,但是很快就反弹回去了)

图2 谷歌商店应用转化率增加幅度 / 10M [1]

因此2022年9月开始我们针对金融APP进行了瘦身专项整治,在不考虑增量的情况,无删减业务代码的情况下实现从117M瘦身至74M,在本次安装包瘦身过程中我们遇到了不少坑,同时也积累了些经验,在此分享给大家。

二、APK分析

接下来我们会简单分析下 Apk内各组成部分,以及 Apk 作为 ZIP,其标准结构是什么样的,为包瘦身的目标设定及任务拆解提供数据支撑。

2.1 APK内容分析

图3 APK 结构

•classes.dex APK 中可能包含一个或多个 classes.dex 文件,应用程序内的 Java/Kotlin 源码最终会以字节码的方式存在于 classes.dex 文件中。

•resources.arscaapt工具在编译资源会将一些资源或者资源索引打包成resources.arsc。

•res/ 源码工程中 res 目录下除了 values 外的资源文件,这些文件路径同时会记录在 resources.arsc 中。

•lib/ nativeLibraries,即源码工程 jni 目录下的 so 文件,二级目录为 NDK支持的 ABI。

•assets/ 与 res/ 资源目录不同,assets/ 下的资源文件不会在 resources.arsc 中生成查询条目,且 assets/ 下的资源目录可完全自定义,在程序中通过 AssetManager 对象来获取。

•META-INF/该文件夹下主要包含 CERT.SF 和 CERT.RSA 签名文件, 以及 MANIFEST.MF 清单文件。

•AndroidManifest.xml 应用清单文件,用于描述应用基本信息,主要包括应用包名、应用id、应用组件、所需权限、设备兼容性等。

2.2 SDK大小分析

通过我们自研的能效提升平台Pandora[7],可以直观地看到SDK的大小,如图4所示:

图4 SDK大小排序(包含版本号)

图5 SDK中包含的SO库列表及大小

根据SDK分析后结合业务,来判断哪些业务适合做插件化,进而直观的降低包体积。

2.3 ZIP结构分析

可以用zipinfo命令输出压缩包中每个文件的详细信息日志,用法:zipinfo -l --t --h test.apk > test.txt

输出的日志文件打开如图6所示,每个文件的压缩信息一行,包括文件名、原始大小、压缩后大小等指标:

图6 APK内文件信息大小

对以上日志信息进行逐行解析,根据解混淆后的文件名路径、文件类型进行归类统计,即可得出Apk的总览信息,包括各类型文件的数量、总大小、单一文件大小等指标,并建立文件大小索引。

三、瘦身实践

整体实施路径如图7所示,主要分为:

1.常规技术方案,通过Gradle插件(代码无侵入、自动化)在编译时期完成APP瘦身;

2.进阶技术方案,将部分业务线差别性的通过插件化或者SO动态下载的方式就行改造,业务改造的越多,收益越高;

3.业务优化方案,针对业务线的数据埋点,生成访问UV进行排名,将UV较低的业务线反馈架构委员会,评估是否可以进行下线或者通过进阶技术方案(2)进行改造,进而减小包体积。

图7 整体实施路径

3-1 常规技术方案

3-1-1 图片处理

经过上述的APP的剖析,得出占用体积第一大的还是图片,因此将APP所有含SDK内所有图片在编译打包过程中通过瘦身任务自动完成图片优化处理,整体优化方案如图8所示:

图8 图片优化方案

1.多 DPI 优化:

Android 为了适配各种不同分辨率或者模式的设备,为开发者设计了同一资源多个配置的资源路径,app 通过 resource 获取图片资源时,自动根据设备配置加载适配的资源,但这些配置伴随着的问题就是高分辨率的设备包含低分辨率的无用图片或者低分辨率的设备包含高分辨率的无用图片。

一般情况下,针对国内应用市场,App 为了减少包大小,会选用市场占有率最高的一套 dpi(google 推荐 xxhdpi)兼容所有设备。而针对海外应用市场的 APP,大多会通过 AppBundle 打包上传至 Google Play,能够享受动态分发 dpi 这一功能,不同分辨率手机可以下载不同 dpi 的图片资源,因此我们需要提供多套 dpi 来满足所有设备。在项目中,我们的图片有的只有一套 dpi,有的有多套 dpi,针对上述两种场景,我们分别在打包时合并资源、复制资源,减少了包大小。

2.转换为webp格式:

_WebP_是谷歌提供的一种支持有损压缩和无损压缩的图片文件格式,而且可以提供比JPEG或PNG更好的压缩。在Android 4.0(API level 14)中支持有损的WebP图像,在Android 4.3(API level 18)和更高版本中支持无损和透明的WebP图像

因此:我们采用插件在编译时期仅保留针对图片通过Google提供的shell程序进行格式转换,转换成功删除旧的图片,进而达到APK瘦身的效果

3.png压缩

_Pngquant是一个_好用的png压缩工具一个,可以进行有损图片压缩的命令行工具,因此在1和2处理结束后,可以使用_Pngquant_进行二次压缩,达到更优的图片瘦身。

3-1-2 R文件内联优化

DEX里是Java/Kotlin 源码编译后的字节码文件,对DEX的优化其实就是怎么优化字节码文件,DEX中包含大量的资源索引R文件,这里主要讲下如何通过资源ID内联后进行R文件删除,达到APK瘦身的目的:

R文件瘦身的可行性分析

日常开发阶段,在主工程中通过R.xx.xx的方式引用资源,经过编译后R类引用对应的常量会被编译进class中。

setContentView(2131427356);

这种变化叫做内联,内联是java的一种机制(如果一个常量被标记为static final,在java编译的过程中会将常量内联到代码中,减少一次变量的内存寻址)。非主工程中,R类资源ID以引用的方式编译进class中,不会产生内联。

setContentView(R.layout.activity_main);

产生这种现象的原因是AGP打包工具导致的。具体细节,大家可以去查阅一下android gradle plugin在R文件上的处理过程。结论:R类id内联后程序可运行,但并非所有的工程都会自动产生内联现象,我们需要通过技术手段在合适的时机将R类id内联到程序中,内联完成后,由于不再依赖R类文件,则可以将R类文件删除,在应用正常运行的同时,达到包瘦身目的,如图9所示,在编译完成后会产生大量的R文件:

图9 项目R文件生成示意

整体方案如图10所示:

图10 R文件优化流程

注意事项:在替换阶段一定要加入二次检查,防止替换完,运行时出现ResourceNotFind异常,如下所示:

try {
    int value = RManager.checkInt(type, name);
}catch (Exception e){
    String errorMsg = "resource is not found(I),className="+className+",fieldName="+owner+"."+name;
    throw new ResourceNotFoundException(errorMsg);
}
try {
    int[] value = RManager.checkIntArray(type, name);
}catch (Exception e){
    String errorMsg = "resource is not found(I[]),className="+className+",fieldName="+owner+"."+name;
    throw new ResourceNotFoundException(errorMsg);
}

3-1-3 AndResGuard进行资源混淆

1.资源加载过程分析

开发过程中我们通过aapt生成的R.java中的常量来使用资源,而在编译之后使用常量的地方都会被替换为常量的值,如下所示:

final View layout = inflater.inflate(2131165182, container, false);

也就是说我们通过Resource使用一个int数值来查找使用资源。那么Resource是怎么通过int数值找到具体的资源呢?我们解压apk可以看到里面有个resources.arsc文件,这个文件也是由aapt生成,文件中保存着资源id和资源key的映射关系,Resource就是按照这个映射关系找到资源的。

2.resources.arsc:

图11是resources.arsc的里存储的映射关系,resources.arsc可以理解为一个资源映射数据库,根据ID映射其中具体的路径和名称。

图11 resources.arsc解析

通过解压APK后,将资源文件名进行短链处理比如res/layout/hello.xml转换为r/l/a.xml后,然后更改resources.arsc对应的value值,达到整体的瘦身效果。

AndResGuard[5]是微信推出资源优化工具,它的基本思想类似于 ProGuard 中的混淆,可以实现以上方案。

3-1-4 7zip压缩

7zip命令解释:

-t:指定压缩类型,支持7z, xz, split, zip, gzip, bzip2, tar, …

-m:指定压缩算法,默认是Deflate

具体流程如下:

3-1-5 配置CPU架构

根据不同的CPU架构,构建不同的类型的安装包,目前主流设备都是64位机器,因此安卓市场上主要投放的是依据arm64-v8a编译构建的安装包

ndk {
    abiFilters arm64-v8a
}

3-1-6 arsc 压缩

resources.arsc 的压缩体积收益很高,但对其进行压缩会影响启动速度和内存指标。原因是:系统在加载 arsc 文件时,若 arsc 文件未压缩,可使用 mmap 进行内存映射;若 arsc 文件被压缩了,则需要将其解压缩后读取到RAM 缓冲区,会增加内存使用,也会拖慢启动速度。

官方出于同样的考虑,从 targetSdkVersion>=30后不能用这种方式 开始强制要求resources.arsc ,否则会直接安装失败,因此本文不在展开阐述。

3-1-7 国际化语言处理

京东金融App目前仅在国内市场运营,但是接入的大量SDK中加入了几十种语言一样,导致整个体积变大,经过评估可以通过配置 resConfigs 去除无用的语言资源。

defaultConfig {
    resConfigs "zh","en"
}

3-1-8 shrinkResources

shrinkResources:编译过程中用来检测并删除无用资源文件,也就是没有引用的资源

minifyEnabled:用来开启删除无用代码,比如没有引用到的代码,所以如果需要知道资源是否被引用就要配合minifyEnabled使用,只有两者都为true时才会起到真正的删除无效代码和无引用资源的目的。

其作用是将未被引用的资源文件替换为一个体积很小的格式文件(仍存在占位体积,同时保留了该资源条目,所以 resources.arsc 体积并不会减少),可通过 res/raw/keep.xml 文件配置 shrinkMode 和白名单。

buildTypes {
   release {
      // 不显示Log
      buildConfigField "boolean", "LOG_DEBUG", "false"
      //混淆
      minifyEnabled true
      // 移除无用的resource文件
      shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig sign.release
   }
}

3-1-9 编码约束

•尽量少用枚举类型,因为枚举在编译成字节码后,会增加大量体积,如图12所示(22行代码编译后字节码是86行)

图12 枚举类型编译后的字节码对比

•删除不必要的LOG日志输出

3-2 进阶技术方案

SO库动态下载和插件化技术,本质上都属于动态下载的一个范畴,两个方案可以在业务中长期持续使用,在具体使用过程中如何选择,如图13所示:

图13 业务如何选择进阶方案

3-2-1 SO库动态加载

APP中有部分业务不适合做插件化改造,经过拆解发现其中的SO库占比很大,因此可以考虑采用动态下载的方式进行改造,进而实现减小体积。

SO库加载的两种方式

第一种方式我们直接把SO库下载并放到指定目录就可以

第二种方式是通过环境变量设置的目录中进行加载SO库,因此我们需要追加指定的目录到环境变量中,就可以正常加载SO库

System.load("{安全路径}/libxxx.so") 
System.load("xxx") 

1、如何设置APP中SO库的环境变量位置(借鉴Tinker):

final Field pathListField = ShareReflectUtil.findField(classLoader, "pathList");
final Object dexPathList = pathListField.get(classLoader);

final Field nativeLibraryDirectories = ShareReflectUtil.findField(dexPathList, "nativeLibraryDirectories");

List<File> origLibDirs = (List<File>) nativeLibraryDirectories.get(dexPathList);
if (origLibDirs == null) {
    origLibDirs = new ArrayList<>(2);
}
final Iterator<File> libDirIt = origLibDirs.iterator();
while (libDirIt.hasNext()) {
    final File libDir = libDirIt.next();
    if (folder.equals(libDir)) {
        libDirIt.remove();
        break;
    }
}
origLibDirs.add(0, folder);

final Field systemNativeLibraryDirectories = ShareReflectUtil.findField(dexPathList, "systemNativeLibraryDirectories");
List<File> origSystemLibDirs = (List<File>) systemNativeLibraryDirectories.get(dexPathList);
if (origSystemLibDirs == null) {
    origSystemLibDirs = new ArrayList<>(2);
}

final List<File> newLibDirs = new ArrayList<>(origLibDirs.size() + origSystemLibDirs.size() + 1);
newLibDirs.addAll(origLibDirs);
newLibDirs.addAll(origSystemLibDirs);

final Method makeElements = ShareReflectUtil.findMethod(dexPathList, "makePathElements", List.class);

final Object[] elements = (Object[]) makeElements.invoke(dexPathList, newLibDirs);

final Field nativeLibraryPathElements = ShareReflectUtil.findField(dexPathList, "nativeLibraryPathElements");
nativeLibraryPathElements.set(dexPathList, elements);

2、如何删除指定SO库和整个加载流程,如图14所示:

图14 SO库删除和加载流程

3-2-2 插件化

什么是插件化:

插件化是将一个Apk根据业务功能拆分成不同的子Apk(也就是不同的插件),每个子Apk可以独立编译打包,最终发布上线的是集成后的Apk。在Apk使用时,每个插件是动态加载的,插件也可以进行热修复和热更新。

•宿主:主App可以用来加载插件也成为Host

•插件:插件App,被宿主加载的App,可以跟普通的App一样的Apk文件

什么形式的业务适合插件化改造:

•业务相对独立,与宿主App解耦彻底

•改造成本低,收益相对较高

•占用体积较大

经过一些列评估,视频营业符合以上几点,改造后的效果如图15所示:

图15 视频营业厅插件化改造后效果

3-3 业务优化方案

随着业务越来越多,一些陈旧的业务UV越来越低,因此制定了一套业务下线优化流程,如图16所示:

图16 业务优化方案流程

四、管控

瘦身方案的实施很重要,后续的管控不反弹更重要,我们一边做瘦身治理,另一边探索常态化的管控机制,最终沉淀了一套管控规范和管控机制。管控的目的不是限制业务迭代或者新增代码,而是怎么做到在有限的代码中实现其功能,提升工程师日常编码中的瘦身意识。

4.1 SDK接入规范

为防止SDK无序扩张,制定了SDK准入规范,在保证功能的前提下严控SDK体积大小,最大程度控制APP体积反弹。

4.2 管控流程

图17 管控流程

根据增加内容、删除内容、增大内容、减小内容、重复文件、代码治理等资源文件的变动情况结合治理管控规范等进行治理,打包构建完成会跟历史版本就行差量对比,获取变化的内容来评估是否具有优化空间,并给出优化目标,待优化后重新构建打包集成。

五、成果与后续规划

5.1 成果

通过以上措施,京东金融Android版本经过两个季度5个版本的迭代,从117M到现在的74M(图18),整体一直维持在可控的范围内。同时在接下来的版本迭代中,我们会将APK瘦身常态化,始终维持包体积在可控的范围内。

图18 金融APP瘦身成果

5.2 后续规划

持续技术手段优化:

业务的不断堆积迭代,总会产生一些无用的资源,所以安装包瘦身要定期清理这些无用文件和代码;

做好各个版本的监控,对比版本之间的差异,发现可以在不影响业务情况下,使用技术手段优化。

线上管控平台搭建:

前期采用线下的管控治理,实施起来有点耗时,后续我们会完善线上管控平台的搭建,与整个App发布构建平台进行融合,形成流水线的机制,做好管控。

小结:安装包瘦身的探索还有很长的路走,本文也只是列举了一些常用的瘦身方案,对于庞大的项目除了优化外,还有做好项目之间的治理,持续对APP进行体积优化,提升用户体验。


其实想要全面掌握好 Android 性能优化的话,这些知识点你必须要有所了解,如: 内存优化、网络优化、卡顿优化、存储优化……等,其实除了这些,像Framework 底层原理逻辑话,也需要有一定的了解,为了让大家一次都可以了解全,所以将其整合成名为《Android 性能优化核心知识点手册》和《Android Framework核心知识点手册》,大家可以参考下:

《Android 性能调优核心笔记汇总》:https://qr18.cn/FVlo89

《Android 性能监控框架》:https://qr18.cn/FVlo89

《Android Framework核心知识点手册》:https://qr18.cn/AQpN4J

  1. 开机Init 进程
  2. 开机启动 Zygote 进程
  3. 开机启动 SystemServer 进程
  4. Binder 驱动
  5. AMS 的启动过程
  6. PMS 的启动过程
  7. Launcher 的启动过程
  8. Android 四大组件
  9. Android 系统服务 - Input 事件的分发过程
  10. Android 底层渲染 - 屏幕刷新机制源码分析
  11. Android 源码分析实战

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

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

相关文章

openEuler 社区 2023 年 4 月运作报告

概述 过去一个月&#xff0c;openEuler社区全员参与openEuler Developer Day 2023&#xff0c;通过SIG组开放工作会议完成了下个版本的规划。openEuler社区也参加了在新加坡举办的FOSSASIA SUMMIT。 在技术层面&#xff0c;社区不断推进创新&#xff0c;发布新项目&#xff0…

动态规划--01背包问题

01背包问题 背包问题题目最优解结构性质状态转移方程方程理解 递归实现核心思想代码实现用例测试 画表非递归实现核心思路代码实现画表展示 计算哪些物品放入算法思想代码实现 背包问题 题目 0-1背包问题:给定n种物品和一背包。物品的重量是w;,其价值为v; ,背包的容量为C。问…

科普文:国内ChatGPT怎么用,ChatGPT国内怎么用,关于ChatGPT你需要了解的内容应该都在这

在国内用了很长一段时间的ChatGPT&#xff0c;每次跟小白&#xff0c;哪怕是用ChatGPT的人交流的时候&#xff0c;都感觉解释不清&#xff0c;正好今天周末&#xff0c;给大家整理一篇关于ChatGPT的科普文&#xff0c;想要了解或使用ChatGPT的人&#xff0c;一定要看~~~&#x…

html实现经典赛车小游戏

文章目录 1.设计来源1.1 主界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/130580123 html实现经典赛车小游戏源码 html实现经典赛车小游戏源码&#xff0c;1.通过键盘…

如何让flex布局中的一个子元素单独右侧对齐

flex布局中的一个子元素单独右侧对齐 在 Flex布局中&#xff0c;我们经常需要对子元素进行对齐操作。使用 justify-content 和 align-items 可以轻松地对所有子元素进行对齐&#xff0c;但是当我们需要对某个子元素进行单独的对齐时&#xff0c;我们应该怎么做呢&#xff1f; …

【涨知识】PCB板为什么多是绿色的?

拿到一块PCB板时&#xff0c;最直观看到板子上油墨的颜色&#xff0c;就是我们一般指的PCB板颜色。PCB板的颜色多种多样&#xff0c;包括绿色、蓝色、红色和黑色等。 其中&#xff0c;绿色是最常用的&#xff0c;更为大家所熟悉。但为什么PCB板多是绿色呢? 当中缘由&#xff…

exe4j打包Jar成exe文件

1. 进入exe4j官网下载exe4j&#xff0c;安装到自己电脑上。 安装完后运行此软件 2. 在自己电脑上新建一个文件夹&#xff08;名字随便起&#xff09;&#xff0c;文件夹内放入要转换的jar文件&#xff0c;ico格式的图片&#xff0c;jar文件夹&#xff08;含jar文件&#xff09…

fbx sdk的使用介绍

我们平时需要围绕fbx写一些小工具&#xff0c;虽说使用ascii格式的fbx可以直接进行字符串解析&#xff0c;并且网上也有一些基于ascii解析的开源库&#xff0c;但在制作一些通用的工具时&#xff0c;使用fbx sdk进行编写肯定是最好的。 1.下载fbx sdk和cmake 要用cmake生成vi…

Revit:测量自适应点之间的距离和轴网距离标注

一、如何测量自适应点之间的距离 今天在体量中发现怎么用对齐标注测量两个自适应点的距离不正确&#xff0c;只用肉眼来看也是错的。 自适应点时空间中的点&#xff0c;直接测量两个点并不能保证测量的时两个点之间的最短距离&#xff0c;有可能时如图所示我们的空间中测量的并…

初始Redis以及Redis的安装

目录 1.初识Redis 1.1.认识NoSQL 1.1.1.结构化与非结构化 1.1.2.关联和非关联 1.1.3.查询方式 1.1.4.事务 1.1.5.总结 1.2.认识Redis 1.3.安装Redis 1.3.1.依赖库 1.3.2.上传安装包并解压 1.3.3.启动 1.3.4.默认启动 1.3.5.指定配置启动 1.3.6.开机自启 1.初识Re…

(八) 探究基于TCP连接的即时通信系统文件功能的实现

文章目录 一、引言二、实现用户文件功能2.1 打开文件并读取相关信息2.2 实现文件的发送和接收2.3 实现文件的展示和管理 三、代码展示3.1 客户端的关键代码 四、效果展示五、个人经验分享六、如何进一步优化文件功能七、总结 一、引言 即时通信系统的用户文件功能是一项非常重…

JVM Shutdown Hook 机制原理以及源码分析

写在前面 最近看众多框架源码的时候都看到使用到了Shutdown Hook机制。比如下图&#xff1a;SkyWalking、Spring、Tomcat等等框架&#xff0c;几乎只要是Java层面的框架都会使用到此机制。所以&#xff0c;借用论坛给读者写一篇关于JVM Shutdown Hook 机制原理分析以及源码分析…

PS如何安装ZXP扩展插件?

Photoshop如何安装ZXP扩展插件&#xff1f;有些小伙伴不会安装&#xff0c;本文介绍两种安装ZXP扩展的方法&#xff0c;希望对您有帮助。 方法一&#xff1a;手动安装方式 1、把下载好的.zxp扩展名改为.zip&#xff0c;然后解压。 Windows系统&#xff1a;C:\Users[ USER ]\A…

CSS--定位

01-定位 作用&#xff1a;灵活的改变盒子在网页中的位置 实现&#xff1a; 1.定位模式&#xff1a;position 2.边偏移&#xff1a;设置盒子的位置 leftrighttopbottom 相对定位 position: relative 特点&#xff1a; 不脱标&#xff0c;占用自己原来位置显示模式特点保…

系统安全分析与设计

目录 第五章、系统安全分析与设计1、信息系统安全属性2、对称加密技术与非对称加密技术3、信息摘要4、数字签名5、数字信封与PGP6、网络安全6.1、各个网络层次的安全保障6.2、网络威胁与攻击6.3、防火墙 第五章、系统安全分析与设计 1、信息系统安全属性 安全属性 保密性&…

最近想学PMP,有什么要注意和推荐的吗?

我觉得参加PMP的学习和考试有两点需要把握住&#xff0c;一是心态&#xff0c;二是学习方法&#xff1b; 谈心态的话虽然比较虚&#xff0c;因为这个还是要看个人在生活中对事物发展的应对能力与应对突发情况的处理能力&#xff0c;但是简单的谈谈在备考过程中心态的处理还是很…

Docker私有仓库

Docker私有仓库 私有仓库搭建 首先启动docker 拉取私有仓库镜像 [rootserver-a ~]# docker pull registry Using default tag: latest latest: Pulling from library/registry 79e9f2f55bf5: Pull complete 0d96da54f60b: Pull complete 5b27040df4a2: Pull complete e2ead82…

「PDF转长图」无压力:两种简单易学的转换方法!

在加班赶DDL的晚上&#xff0c;你突然接到老板的信息&#xff1a;立刻将这份PDF文件转换成长图并发给我&#xff01;于是你开始了疯狂截图的模式。你是否曾经遇到过这个问题&#xff0c;不知道是否有方便快捷的PDF转长图的解决方法呢&#xff1f; 作为一名资深的PDF专家&#x…

【26】核心易中期刊推荐——机器智能人工神经网络

🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…

诗圣杜甫不同时期的代表作

杜甫一生大致分为四个时期。 中青年时期 青年时&#xff0c;作为官三代的杜甫并不缺钱&#xff0c;四处游历&#xff0c;与李白、高适唱和、仙游&#xff0c;成为佳话。这个时期杜甫的作品热血豪迈&#xff0c;气势蓬勃。代表作首推《望岳》&#xff1a; 岱宗夫如何&#xf…