【NDK系列】Android tombstone文件分析

文件位置

data/tombstone/tombstone_xx.txt

获取tombstone文件命令:

  1. adb shell cp /data/tombstones ./tombstones

触发时机

NDK程序在发生崩溃时,它会在路径/data/tombstones/下产生导致程序crash的文件tombstone_xx,记录了死亡了进程的基本信息(例如进程的进程号,线程号),死亡的地址(在哪个地址上发生了Crash),死亡时的现场是什么样的(记录了一系列的堆栈调用信息)等等。

内容示例

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
Revision: '0'
ABI: 'x86'
pid: 1019, tid: 1019, name: surfaceflinger  >>> /system/bin/surfaceflinger <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4eax a6265c06  ebx b7467d88  ecx b7631a22  edx a6265c06esi 00000000  edi b6867140xcs 00000073  xds 0000007b  xes 0000007b  xfs 00000000  xss 0000007beip b745a639  ebp bfcfc1e8  esp bfcfc150  flags 00010282backtrace:#00 pc 00006639  /system/lib/libui.so (android::Fence::waitForever(char const*)+41)#01 pc 00034b86  /system/lib/libsurfaceflinger.so#02 pc 0003229e  /system/lib/libsurfaceflinger.so#03 pc 0002cb9c  /system/lib/libgui.so (android::BufferQueue::ProxyConsumerListener::onFrameAvailable(android::BufferItem const&)+652)#04 pc 000342f4  /system/lib/libgui.so (android::BufferQueueProducer::queueBuffer(int, android::IGraphicBufferProducer::QueueBufferInput const&, android::IGraphicBufferProducer::QueueBufferOutput*)+2580)#05 pc 0004eafb  /system/lib/libgui.so (android::Surface::queueBuffer(ANativeWindowBuffer*, int)+411)#06 pc 0004ce06  /system/lib/libgui.so (android::Surface::hook_queueBuffer(ANativeWindow*, ANativeWindowBuffer*, int)+38)#07 pc 00014bc6  /system/lib/egl/libGLES_android.so#08 pc 00017f73  /system/lib/egl/libGLES_android.so (eglSwapBuffers+163)#09 pc 00015fdb  /system/lib/libEGL.so (eglSwapBuffers+203)#10 pc 000013ea  /system/lib/hw/hwcomposer.x86.so#11 pc 00034730  /system/lib/libsurfaceflinger.so#12 pc 000256d4  /system/lib/libsurfaceflinger.so#13 pc 00024bf4  /system/lib/libsurfaceflinger.so#14 pc 000236fb  /system/lib/libsurfaceflinger.so#15 pc 0002338a  /system/lib/libsurfaceflinger.so#16 pc 0001e0ff  /system/lib/libsurfaceflinger.so#17 pc 0001d9ce  /system/lib/libutils.so (android::Looper::pollInner(int)+926)#18 pc 0001db73  /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+67)#19 pc 0001e561  /system/lib/libsurfaceflinger.so#20 pc 00022ce7  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::run()+39)#21 pc 00000ca3  /system/bin/surfaceflinger#22 pc 0001365a  /system/lib/libc.so (__libc_init+106)#23 pc 00000da8  /system/bin/surfaceflingerstack:bfcfc110  00000000  bfcfc114  b6839270  bfcfc118  00000000  bfcfc11c  00000000  bfcfc120  b68394e0  bfcfc124  00000002  bfcfc128  00000002  bfcfc12c  b75d8185  /system/lib/libutils.so (android::RefBase::incStrong(void const*) const+53)bfcfc130  b6839270  bfcfc134  bfcfc1e8  [stack]bfcfc138  00000002  bfcfc13c  a6265c06  bfcfc140  b7467d88  /system/lib/libui.sobfcfc144  00000000  bfcfc148  b6867140  bfcfc14c  b745a639  /system/lib/libui.so (android::Fence::waitForever(char const*)+41)#00  bfcfc150  b683af18  bfcfc154  bfcfc1e8  [stack]bfcfc158  00000000  bfcfc15c  00000000  bfcfc160  00000000  bfcfc164  b683af18  bfcfc168  b75ec9c4  /system/lib/libutils.sobfcfc16c  b75d8285  /system/lib/libutils.so (android::RefBase::weakref_type::decWeak(void const*)+37)bfcfc170  00000000  bfcfc174  00000000  bfcfc178  00000000  bfcfc17c  00000000  bfcfc180  b7642968  /system/lib/libsurfaceflinger.sobfcfc184  bfcfc1e8  [stack]bfcfc188  b6867140  bfcfc18c  b7622b87  /system/lib/libsurfaceflinger.so

构建指纹

Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'

典型的格式为:AOSP/[Android Version]/[Build ID]/[Build Date]

  • “Android-x86”: 表示Android-x86工程
  • “android_x86”: 表示Android-x86工程的分支名或者构建变体
  • “x86:5.1.1”: 表示安卓版本为5.1.1, 即Lollipop。"x86"表示其针对x86架构CPU进行优化
  • “LMY48W”: 表示构建号(build number),构建号可以自定义,比如某个feature、bugfix的提交号
  • “woshijpf04211939:eng”: 自定义标签,比如构建者、构建目等,“eng” 可能表示使用了engineering配置
  • “test-keys”: 表示此构建使用了测试key而不是正式发布的key文件

崩溃的过程和PID

pid: 1019, tid: 1019, name: surfaceflinger  >>> /system/bin/surfaceflinger <<<

如果pid等于tid,那么就说明这个程序是在主线程中Crash掉的,名称的属性则表示Crash进程的名称以及在文件系统中位置。

终止信号和故障地址

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4

信息说明出现进程Crash的原因是因为程序产生了段错误的信号,访问了非法的内存空间,而访问的非法地址是0x4。

典型的内存地址访问错误:

  1. 野指针
  2. 内存泄露
  3. 堆栈溢出
  4. 初始化错误
  5. 类型转换错误
  6. 数字除0

Linux信号机制

崩溃信号列表

在这里插入图片描述
信号机制是Linux进程间通信的一种重要方式,Linux信号一方面用于正常的进程间通信和同步,如任务控制(SIGINT,SIGTSTP,SIGKILL,SIGCONT,…);另一方面,它还负责监控系统异常及中断。当应用程序运行异常时,Linux内核将产生错误信号并通知当前进程。当前进程在接收到该错误信号后,可以有三种不同的处理方式:

  1. 忽略该信号。
  2. 捕捉该信号并执行对应的信号处理函数(信号处理程序)。
  3. 执行该信号的缺省操作(如SIGSEGV,其缺省操作是终止进程)。

当Linux应用程序在执行时发生严重错误,一般会导致程序崩溃。其中,Linux专门提供了一类crash信号,在程序接收到此类信号时,缺省操作是将崩溃的现场信息记录到核心文件,然后终止进程。

CPU寄存器

调用堆栈

backtrace:#00 pc 00006639  /system/lib/libui.so (android::Fence::waitForever(char const*)+41)#01 pc 00034b86  /system/lib/libsurfaceflinger.so#02 pc 0003229e  /system/lib/libsurfaceflinger.so#03 pc 0002cb9c  /system/lib/libgui.so (android::BufferQueue::ProxyConsumerListener::onFrameAvailable(android::BufferItem const&)+652)#04 pc 000342f4  /system/lib/libgui.so (android::BufferQueueProducer::queueBuffer(int, android::IGraphicBufferProducer::QueueBufferInput const&, android::IGraphicBufferProducer::QueueBufferOutput*)+2580)
  • #00,#01,#02表示函数调用栈中栈帧的编号,编号越小的栈帧表示着当前最近调用的函数信息,所以栈帧标号#00表示的就是当前正在执行并导致程序崩溃函数的信息。
  • pc后面的16进制数值表示的是当前函数正在执行的语句在共享链接库或者可执行文件中的位置
  • /system/lib/libui.so表示的是当前执行指令是在哪个文件当中
  • 小括号则是注明对应的是哪个函数
    例如,在上面的例子中,我们就可以定位到是程序是在Fence :: waitForever(char const *)中出现了错误,但是具体在那一行呢,我们还不是特别清楚,所以就需要我们进一步地使用更加高级的工具来帮助我们解析tombstone中有关调用栈的信息。

堆叠每个通话的内容

处理工具

Google在NDK包中为我们提供了一系列的调试工具:

  • addr2line
  • objdump
  • ndk-stack

在介绍上述工具的使用方法之前有必要再次介绍一下so文件的构成,虽然这部分内容属于NDK范畴。

so文件介绍

so文件组成

完整的 .so 文件由 C/C++代码和一些 debug 信息组成,这些 debug 信息会记录 .so中所有方法的对照表,就是方法名和其偏移地址的对应表,也叫做符号表symbolic 信息,这种.so被称为未strip的,通常体积会比较大。

注意:

  1. 符号表可以类比为 Java 代码混淆中的 mapping 文件,只有拥有这个 mapping 文件才能进行堆栈分析。
  2. 编译完so文件后,需要保留「机器码+debug信息的完整so文件」或者「仅含debug信息的符号表文件」

在这里插入图片描述

可以通过file命令查看so文件基本信息,以判断是否包含debug信息:

# 查看已被stripped的so文件
file libbreakpad-core-s.so
libbreakpad-core-s.so: *******, BuildID[sha1]=54ad86d708f4dc0926ad220b098d2a9e71da235a, stripped
# 查看未被stripped的so文件
file libbreakpad-core.so
libbreakpad-core.so: ******, BuildID[sha1]=54ad86d708f4dc0926ad220b098d2a9e71da235a, with debug_info, not stripped

so文件获取

目前 Android Studio 无论是使用 mk 或者 Cmake 编译的方式都会同时输出 strip 和未 strip 的 so:

  • strip 之前的 so 路径:{project}/app/build/intermediates/merged_native_libs
  • strip 之后的 so 路径:{project}/app/build/intermediates/stripped_native_libs

如下图是 Cmake 编译 so 产生的两个对应的 so:

图片 1 图片 2

addr2line

该工具通过输入so文件和backtrace中的地址来输出源码中的行号,支持一次性输入多个地址。

工具路径:

  • Mac OS:$NDK_ROOT/toolchains/x86-4.9/prebuilt/darwin-x86_64/bin/i686-linux-android-addr2line

最佳实践:

alias addr2line='$NDK_HOME/toolchains/x86-4.6/prebuilt/linux-x86/bin/i686-linux-android-addr2line'

注意:

  1. so文件需要带符号表,位于out/target/product/cc_company/symbols/system/lib
  2. 由于是逐行解析,因此想要得到完整的源码调用栈需要自行封装写个脚本工具;

用法

Usage:android-addr2line [option(s)] [addr(s)]Convert addresses into line number/file name pairs.If no addresses are specified on the command line, they will be read from stdinThe options are:@<file>                Read options from <file>-a --addresses         Show addresses-b --target=<bfdname>  Set the binary file format-e --exe=<executable>  Set the input file name (default is a.out)-i --inlines           Unwind inlined functions-j --section=<name>    Read section-relative offsets instead of addresses-p --pretty-print      Make the output easier to read for humans-s --basenames         Strip directory names-f --functions         Show function names-C --demangle[=style]  Demangle function names-h --help              Display this information-v --version           Display the program's versionandroid-addr2line: supported targets: elf32-i386 elf32-iamcu a.out-i386-linux pei-i386 elf64-x86-64 elf32-x86-64 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
Report bugs to <http://www.sourceware.org/bugzilla/>

推荐:add2line -fCp -e /path/to/xxx.so \<addresses\>

示例

执行命令:
addr2line -f -e libui.so 00006639

输出结果:

_ZN7android5Fence11waitForeverEPKc
/home/woshijpf/newspace/android-x86/frameworks/native/libs/ui/Fence.cpp:59

ndk-stack

可将墓碑文件中的backtrace和stack完整还原成源码文件路径+代码行号的呈现方式。

工具路径:$NDK_HOME/ndk-stack

注意:

  1. 需要obj目录,例如obj/local/x86/
  2. 通常用于本地调试阶段的问题排查,对于线上问题排查时不一定保留这些符号表文件

用法

Usage:ndk-stack -sym <path> [-dump <path>]-sym  Contains full path to the root directory for symbols.-dump Contains full path to the file containing the crash dump.This is an optional parameter. If ommited, ndk-stack willread input data from stdin
  • sym: 需要输入符号表文件的根目录,即obj目录
  • dump:输入指定的trace文本文件路径或者若缺省则从标准输入读取

示例

原墓碑文件内容:

// tombstone_01 文件内容
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
Revision: '0'
ABI: 'x86'
pid: 2125, tid: 2125, name: androidvncserve  >>> androidvncserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0eax 00000000  ebx b76ffff4  ecx b6a37000  edx 00000000esi 00000000  edi 00000000xcs 00000073  xds 0000007b  xes 0000007b  xfs 00000000  xss 0000007beip b75a4ec5  ebp bfa9bd08  esp bfa9bbf0  flags 00010246backtrace:#00 pc 0004bec5  /system/bin/androidvncserver#01 pc 0004e3e4  /system/bin/androidvncserver#02 pc 0001365a  /system/lib/libc.so (__libc_init+106)#03 pc 0001060c  /system/bin/androidvncserverstack:bfa9bbb0  bfa9bbc8  [stack]bfa9bbb4  b72c6fb0  /system/lib/libdvnc_flinger_sdk22.sobfa9bbb8  b72c7004  /system/lib/libdvnc_flinger_sdk22.sobfa9bbbc  b72c5b26  /system/lib/libdvnc_flinger_sdk22.so (readfb_flinger+38)bfa9bbc0  b68ae080  bfa9bbc4  00000000  bfa9bbc8  00000000  bfa9bbcc  00000000  bfa9bbd0  00000000  bfa9bbd4  b76ffff4  /system/bin/androidvncserverbfa9bbd8  b76a5e20  /system/bin/androidvncserverbfa9bbdc  b75ac181  /system/bin/androidvncserverbfa9bbe0  b75ac16b  /system/bin/androidvncserverbfa9bbe4  b76ffff4  /system/bin/androidvncserverbfa9bbe8  bfa9bd08  [stack]bfa9bbec  b75a579b  /system/bin/androidvncserver#00  bfa9bbf0  00000012  bfa9bbf4  bfa9bc1c  [stack]bfa9bbf8  00000000  bfa9bbfc  00000000  bfa9bc00  bfa9bc14  [stack]bfa9bc04  00000000  bfa9bc08  00000000  bfa9bc0c  b7498825  /system/lib/libc.so (je_free+453)bfa9bc10  0000000e  bfa9bc14  00000400  bfa9bc18  00000000  bfa9bc1c  b749538a  /system/lib/libc.so (je_malloc+778)bfa9bc20  0000000c  bfa9bc24  00000065  bfa9bc28  00000000  bfa9bc2c  b6a37000  ........  ........#01  bfa9bd10  b6bb7300  bfa9bd14  00001b58  bfa9bd18  b76aa954  /system/bin/androidvncserverbfa9bd1c  0000000b  bfa9bd20  00000005  bfa9bd24  00000000  bfa9bd28  00000000  bfa9bd2c  00000005  bfa9bd30  00000006  bfa9bd34  00000005  bfa9bd38  00000000  bfa9bd3c  00000000  bfa9bd40  00000000  bfa9bd44  bfa9bd24  [stack]bfa9bd48  b754f9c8  /system/bin/linkerbfa9bd4c  b7557bd8  /system/bin/linker........  ........#02  bfa9bed0  00000001  bfa9bed4  bfa9bf14  [stack]bfa9bed8  bfa9bf1c  [stack]bfa9bedc  00000000  bfa9bee0  b7556fec  /system/bin/linkerbfa9bee4  bfa9bf10  [stack]bfa9bee8  00000000  bfa9beec  b7556fec  /system/bin/linkerbfa9bef0  bfa9bf10  [stack]bfa9bef4  00000000  bfa9bef8  bfa9bf0c  [stack]bfa9befc  b756960d  /system/bin/androidvncserver#03  bfa9bf00  bfa9bf10  [stack]bfa9bf04  00000000  bfa9bf08  b756960d  /system/bin/androidvncserverbfa9bf0c  b7569612  /system/bin/androidvncserverbfa9bf10  00000001  bfa9bf14  bfa9cb05  [stack]bfa9bf18  00000000  bfa9bf1c  bfa9cb16  [stack]bfa9bf20  bfa9cb35  [stack]bfa9bf24  bfa9cb48  [stack]bfa9bf28  bfa9cba3  [stack]bfa9bf2c  bfa9cbae  [stack]bfa9bf30  bfa9cbc1  [stack]bfa9bf34  bfa9cbdc  [stack]bfa9bf38  bfa9cbe7  [stack]bfa9bf3c  bfa9cbfd  [stack]

执行命令:
ndk-stack -sym obj/local/x86/ -dump ~/android-x86-debug-log/tombstone_01

输出结果:

********** Crash dump: **********
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
pid: 2125, tid: 2125, name: androidvncserve  >>> androidvncserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
Stack frame #00 pc 0004bec5  /system/bin/androidvncserver: Routine update_screen_16 in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/updateScreen.c:68
Stack frame #01 pc 0004e3e4  /system/bin/androidvncserver: Routine main in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/droidvncserver.c:805
Stack frame #02 pc 0001365a  /system/lib/libc.so (__libc_init+106)
Stack frame #03 pc 0001060c  /system/bin/androidvncserver: Unable to locate routine information for address 1060c in module obj/local/x86//androidvncserver
Stack frame #00 pc 0007bf71  /system/lib/libc.so (nanosleep+17)
Stack frame #01 pc 00047ed6  /system/lib/libc.so (usleep+70)
Stack frame #02 pc 0004fa6b  /system/bin/androidvncserver: Routine camera_io in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/camera_io.c:557
Stack frame #03 pc 0004af6a  /system/bin/androidvncserver: Routine receive_camera in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/droidvncserver.c:273
Stack frame #04 pc 00022168  /system/lib/libc.so (__pthread_start(void*)+56)
Stack frame #05 pc 0001cc69  /system/lib/libc.so (__start_thread+25)
Stack frame #06 pc 000137c6  /system/lib/libc.so (__bionic_clone+70)
Stack frame #00 pc 0007cc33  /system/lib/libc.so (recvfrom+19)
Stack frame #01 pc 00050cdb  /system/bin/androidvncserver: Routine handle_connections in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/gui.c:105
Stack frame #02 pc 00022168  /system/lib/libc.so (__pthread_start(void*)+56)
Stack frame #03 pc 0001cc69  /system/lib/libc.so (__start_thread+25)
Stack frame #04 pc 000137c6  /system/lib/libc.so (__bionic_clone+70)

objdump

使用objdump命令对目标文件(obj)或可执行文件进行反汇编,它以一种可阅读的格式让你更多的了解二进制文件可能带有的附加信息。

参考文章:objdump的使用

参考资料

  • 谷歌官方教程:调试 Android 平台原生代码
  • Android NDK墓碑/崩溃分析_android墓碑文件_Lixby的博客-CSDN博客
  • Android的墓碑 - 掘金
  • Android 平台 Native Crash 问题分析与定位

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

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

相关文章

【C++入门】缺省参数 | 函数重载

目录 4.缺省参数 4.1缺省参数的概念 4.2缺省参数分类 4.3声明和定义分离&#xff08;声明使用缺省参数&#xff09; 4.&#x1f40d;声明和定义分离到链接 5.函数重载 5.1函数重载的概念 5.2可执行程序的形成步骤 5.3C支持函数重载的原理—名字修饰(name Mangling) 4.…

180基于matlab的频率切片小波变换程序(FTWT)

基于matlab的频率切片小波变换程序&#xff08;FTWT&#xff09;。从一种新的角度出发&#xff0c;通过自由选择频率切片函数、引进新尺度参数&#xff0c;在频率域实现小波变换&#xff0c;该变换能够很好地刻画信号各成分之间的相对能量关系。此外&#xff0c;频率切片小波变…

YOLOv9有效提点|加入SGE、Ge、Global Context、GAM等几十种注意力机制(四)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文只有代码及注意力模块简介&#xff0c;YOLOv9中的添加教程&#xff1a;可以看这篇文章。 YOLOv9有效提点|加入SE、CBAM、ECA、SimA…

超强预测算法:XGBoost预测模型

目录 往期精彩内容&#xff1a; 多变量特征序列、单序列数据预测实战 前言 1 风速数据预处理与数据集制作 1.1 导入数据 1.2 多变量数据预处理与数据集制作 1.3 单序列数据预处理与数据集制作 2超强模型XGBoost——原理介绍 3 模型评估和对比 3.1 随机森林预测模型 3…

蓝桥杯Java B组历年真题(2013年-2021年)

一、2013年真题 1、世纪末的星期 使用日期类判断就行&#xff0c;这里使用LocalDate&#xff0c;也可以使用Calendar类 答案 2099 使用LocalDate import java.time.LocalDate; import java.time.format.DateTimeFormatter; // 1:无需package // 2: 类名必须Main, 不可修改p…

重生奇迹mu魔法师用什么技能刷怪

1、在重生奇迹mu中&#xff0c;魔法师刷怪可采用多种技能。其中&#xff0c;火球术、冰箭术、雷电术、火墙术、冰咆哮术等单体伤害技能较为常用&#xff0c;可以快速消灭单个怪物。 2、同时&#xff0c;群体伤害技能如流星雨、冰风暴、雷霆一击等也可在多个怪物间快速切换&…

MVCC及其原理

1. MVCC概述及其原理 多版本并发控制&#xff08;MVCC&#xff0c;Multi-Version Concurrency Control&#xff09;是一种数据库管理技术&#xff0c;用于提高数据库系统在多用户环境中的并发性能&#xff0c;同时保证事务的隔离性&#xff0c;避免了不必要的锁定。MVCC允许在…

详解JavaScript的函数

详解 JavaScript 的函数 函数的语法格式 创建函数/函数声明/函数定义 function 函数名(形参列表) { 函数体 return 返回值; // return 语句可省略 } 函数调用 函数名(实参列表) // 不考虑返回值 返回值 函数名(实参列表) // 考虑返回值 示例代码 //定义的没有参数列表&am…

鸿蒙Harmony应用开发—ArkTS声明式开发(触摸事件)

当手指在组件上按下、滑动、抬起时触发。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 onTouch onTouch(event: (event: TouchEvent) > void) 手指触摸动作触发该回调。 卡片能力&#xff1a; 从…

备战蓝桥杯Day22 - 计数排序

计数排序问题描述 对列表进行排序&#xff0c;已知列表中的数范围都在0-100之间。设计时间复杂度为O(n)的算法。 比如列表中有一串数字&#xff0c;2 5 3 1 6 3 2 1 &#xff0c;需要将他们按照从小到大的次序排列&#xff0c;得到1 1 2 2 3 3 5 6 的结果。那么此时计数排序是…

2000-2021年300+地级市进出口总额数据

2000-2021年300地级市进出口总额数据 1、时间&#xff1a;2000-2021年 2、指标&#xff1a;进出口总额 3、单位&#xff1a;万美元 4、来源&#xff1a;城市年鉴、各省年鉴、城市公报、2021年为城市统计年鉴中进口额出口额加总之后换算成万美元&#xff0c;已尽最大可能进行…

机器学习:集成学习(Python)

一、Adaboost算法 1.1 Adaboost分类算法 adaboost_discrete_c.py import numpy as np import copy from ch4.decision_tree_C import DecisionTreeClassifierclass AdaBoostClassifier:"""adaboost分类算法&#xff1a;既可以做二分类、也可以做多分类&#…