JVM学习之内存与垃圾回收篇1

文章目录

  • 1 JVM与Java体系结构
    • 1.0 Java发展重大事件
    • 1.1 虚拟机和Java虚拟机
    • 1.3 JVM整体结构
    • 1.4 Java代码执行流程
    • 1.5 JVM架构模型
    • 1.6 JVM的生命周期
    • 1.7 JVM发展历程
  • 2 类加载子系统
    • 2.1 ClassLoader
    • 2.2 用户自定义类加载器
      • 2.2.1 为什么需要自定义类加载器
      • 2.2.2 自定义类加载器的实现步骤
    • 2.3 双亲委派机制
    • 2.3 类的加载过程
    • 2.4 其他
  • 参考材料

1 JVM与Java体系结构

1.0 Java发展重大事件

2000年,JDK 1.3发布,Java Hot Spot Virtual Machine正式发布,成为Java的默认虚拟机。
2006年,JDK 6发布。同年,Java开源并建立了OpenJDK。顺理成章,Hotspot虚拟机也成为了OpenJDK中的默认虚拟机。
2008年,Oracle收购了BEA,得到了JRockit虚拟机。
2010年,Oracle收购了Sun,获得了Java的商标和HotSpot虚拟机。
2011年,JDK 7 中正式启用G1垃圾收集器。
2017年,JDK 9 中G1成为默认的GC,代替CMS。IBM也开源了J9 虚拟机。
2018年,JDK 11 LTS版本,发布革命性的ZGC,调整jdk授权许可。
2019年, JDK 12发布,增加了Shenandoah gc。

1.1 虚拟机和Java虚拟机

虚拟机,就是虚拟的计算机,是用来执行一系列虚拟计算机指令的软件。大体可以分为系统虚拟机和程序虚拟机。

Visual Box,VMWare就是系统虚拟机,它们完全是对物理计算机的仿真,提供了一个可运行的完整的操作系统软件平台。 Java虚拟机就是典型的程序虚拟机,它专门为执行单个计算机程序而设计。

无论是哪种虚拟机,其上所运行的软件都被限制于虚拟机提供的资源中。

Java虚拟机就是一台执行字节码(这个字节码可以是Java语言生成的,也可以是其他语言生成的)的虚拟计算机。

在这里插入图片描述

1.3 JVM整体结构

在这里插入图片描述

1.4 Java代码执行流程

java源码(xxx.java)
编译(前端编译):词法分析、语法分析、语法/抽象语法树、语义分析、注解抽象语法树和字节码生成器。
字节码(xxx.class)
Java虚拟机:类加载器,字节码校验器,字节码解释器和JIT编译器
二进制指令
操作系统

1.5 JVM架构模型

Java编译器输入的指令流基本上是一种基于栈的指令集架构,另外一种指令架构是基于寄存器的指令架构
栈式架构特点:

  1. 设计和实现更简单,适用于资源受限的系统。
  2. 避开了寄存器分配难题:使用零地址指令方式分配。
  3. 指令流中的指令大部分是零地址指令,其执行过程依赖于操作栈。指令集更小(单条指令更短),编译器容易实现。
  4. 不需要硬件支持,可移植性更好,更好实现跨平台。

寄存器式架构特点:
5. 典型应用是x86的二进制指令集:传统pc以及Android的Davlik虚拟机。
6. 指令集架构完全依赖硬件,可移植性差。
7. 性能优秀和执行高效。
8. 花费更少的指令(指令条数少)去完成一项操作。
9. 大部分情况下, 基于寄存器架构的指令集往往都以一地址指令、二地址指令和三地址指令为主。基于栈的指令架构往往以零地址指令为主。

举例:两种指令架构下实现2+3

iconst_2  // 常量2入栈
istore_1
iconst_3 // 常量3入栈
istore_2
iload_1
iload_2
iadd // 常量2,3出栈,执行相加
istore_0  // 结果5入栈
mov eax,2 // eax 初始值设置为2
add eax,3 // 将寄存器内的值+3

1.6 JVM的生命周期

【启动】
Java虚拟机的启动是通过引导类加载器(Bootstrap class loader)创建一个初始类(initial class)来完成的,这个类由虚拟机的具体实现指定的。
【执行】
一个运行中的Java虚拟机有一个清晰的任务:执行java程序。
程序开始执行时它才运行,程序结束时它就停止。
执行一个Java程序的时候,真正执行的是一个Java虚拟机的进程。
【退出】

  • 程序正常执行结束
  • 程序在执行过程中遇到了异常或者错误而异常终止
  • 由于操作系统出现错误而导致Java虚拟机进程终止。
  • 某线程调用Runtime类或者System类的exit方法,或者调用Runtime类的halt方法,并且Java安全管理器也允许这次exit或者halt操作。
  • JNI规范描述了用JNI Invocation API来加载或者卸载Java虚拟机时,Java虚拟机退出。

1.7 JVM发展历程

【Sun Classic VM】
1996年,JDK1.0发布了第一款商用的java虚拟机,Sun Classic VM。jdk 1.4的时候被淘汰掉了。
此VM只提供解释器
如果要使用jit编译器,需要进行外挂。一旦使用了JIT,JIT就会接管虚拟机的执行系统。解释器就不再工作。解释器和编译器不能配合工作。
现在HotSpot虚拟机中内置了此虚拟机。

【Exact VM】

  • jdk1.2时提供了此虚拟机。
  • Exact Memory Management:准确式内存管理。 虚拟机可以知道内存中某个位置的数据具体是什么类型。
  • 具备现代高性能虚拟机的雏形:(1)热点探测(2)编译器与解释器的混合工作模式。
  • 只在Solaris平台短暂使用过。 最终被Hotspot取代。

【HotSpot VM】

  • jdk1.3的时候成为了默认的虚拟机。
  • 占有绝对的市场地位,称霸武林。 Oracle jdk和OpenJDK中都是默认的虚拟机。
  • 使用热点探测技术。通过计数器找到最有编译价值的代码,触发即时编译或者栈上替换。通过编译器和解释器协同工作,在最优化响应时间和最佳执行性能中取得平衡。

【JRockit VM】

  • 专注于服务端应用。 不关注启动速度,内部不包含解释器,全部代码依靠即时编译器编译后执行。
  • 最快的JVM

【J9】

  • IBM公司所有
  • 号称是最快的虚拟机。 主要是在IBM的产品上使用效果比较好。

【Azul VM】

  • 与特定硬件平台绑定,软硬件配合的专有虚拟机。
  • 每个Azul VM实例都可以管理至少数十个CPU和数百个GB内存的硬件资源,并提供在巨大的内存范围内实现可控的GC时间的垃圾收集器、专有硬件优化的线程调度等优秀特征。

【Liquid VM】

  • 与特定硬件平台绑定,软硬件配合的专有虚拟机。
  • Liquid VM不需要操作系统的支持,或者说它本身实现了一个专用操作系统的必要功能,如线程调度、文件系统和网络支持等。

【Apache Harmony】

  • 它的Java类库代码被吸收进了Android SDK中。

【Micorsoft JVM】

  • 初衷是为了在IE浏览器中支持Java Applets,只能在windows平台下运行,是当时windows平台下性能最好的Java VM
  • 1997年,因为侵犯商标,不正当竞争等罪名,此VM下架了。

【TaobaoJVM】

  • 阿里基于OpenJDK开发了自己定制化的AlibabaJDK
  • 是深度定制且开源的高性能服务器版的Java虚拟机。
  • GCIH(GC Invisible heap)技术实现了off-heap,即将生命周期较长的Java对象从heap中搬移到heap之外,并且GC不能管理GCIH内部的Java对象,以此达到降低GC回收频率和提升GC的回收效率的目的。
  • GCIH中的对象能够在多个虚拟机进程中实现共享。
  • 严重依赖intel的cpu,损失了兼容性,提高了性能。

【Dalvik VM】

  • Goolge开发的,应用于Android系统,并在Android2.2中提供了JIT
  • Dalvik VM只能称为虚拟机,不能称为“Java虚拟机”,它没有遵循Java虚拟机规范。
  • 执行的是dex(Dalvik Executable)文件,效率较高。dex文件可以通过classes文件转化而来。
  • 基于寄存器的指令架构
  • Android 5.0使用支持提前编译(Ahead of Time Compilation, AOT)的ART VM替换掉Dalvik VM。

【Graal VM】

  • 2018.04 Oracle Labs公开
  • Run Programmes Faster Anywhere
  • 跨语言全栈虚拟机,可以作为“任何语言”的运行平台。包括c和cpp。

2 类加载子系统

2.1 ClassLoader

在这里插入图片描述
ClassLoader是可以有多个的。

文件头特定的文件标识就是“咖啡baby”。
在这里插入图片描述
在这里插入图片描述
所有的类加载器不是继承关系,可以看做是等级关系,永远都是最高等级的bootstrap先加载对象,其加载不了的才轮到后面。

【Bootstrap类加载器】
bootstrap加载器加载jre/lib/rt.jarresources.jar或者sun.boot.class.path路径中的内容,Object类,String类,ArrayList等都是其加载的。
查看启动类加载器的加载路径

URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();

加载扩展类和应用程序类加载器,并指定为他们的父类加载器。
出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类。

【Ext类加载器】
扩展类加载器加载的是 jre/lib/ext/*.jar中的内容。
如果用户创建jar包也放在了ext目录中, 也会自动由ext类加载器进行加载。

查看扩展类加载器的加载路径

String extDirs = System.getProperty("java.ext.dirs");
String dirArr = extDirs.split(";");

【系统类加载器】
应用程序类加载器加载Java编码中自定义的对象。
负责加载环境变量classpath或者系统属性java.class.path指定路径下的类库。
系统类加载器是程序中默认的类加载器,一般来说,Java应用的类都有它来完成。
可以通过如下方式获取到此类加载器:ClassLoader.getSystemClassLoader()

验证用例程序

package org.example.classloader;

import com.sun.nio.zipfs.JarFileSystemProvider;

public class ClassLoaderTest {
    public static void main(String[] args) {
        Object o = new Object();
        System.out.println(o.getClass().getClassLoader()); // bootstrap class loader 获得不到的,返回值为null

        System.out.println("==========================================");

        MyObject myObject = new MyObject();
        System.out.println(myObject.getClass().getClassLoader());
        System.out.println(myObject.getClass().getClassLoader().getParent());
        System.out.println(myObject.getClass().getClassLoader().getParent().getParent());

        System.out.println("==========================================");

        JarFileSystemProvider provider = new JarFileSystemProvider();
        System.out.println(provider.getClass().getClassLoader());
        System.out.println(provider.getClass().getClassLoader().getParent());
    }
}

class MyObject {

}


null
==========================================
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@14ae5a5
null
==========================================
sun.misc.Launcher$ExtClassLoader@14ae5a5
null

从JVM规范的角度上讲,类加载器分为两种:引导类加载器(Bootstrap ClassLoader)和自定义类加载器(User-defined ClassLoader)。Java虚拟机规范中将所有的派生于ClassLoader的类加载器全部划归为自定义类加载器。

获取classLoader的方式:

  1. 获取一个类的ClassLoader
clazz.getClassLoader();
  1. 获取当前线程上下文的ClassLoader
Thread.currentThread().getContextClassLoader();
  1. 获取系统的ClassLoader
ClassLoader.getSystemClassLoader();
  1. 获取调用者的ClassLoader
DriverManger.getCallerClassLoader();

2.2 用户自定义类加载器

2.2.1 为什么需要自定义类加载器

  • 隔离类加载器
  • 修改类加载方式
  • 扩展加载源
  • 防止源码泄漏

2.2.2 自定义类加载器的实现步骤

  1. 继承抽象类java.lang.ClassLoader, 建议把自定义的类加载逻辑放在findClass()方法中。
  2. 如果没有特别复杂的需求,可以直接继承URLClassLoader,这样可以避免自己去写findClass方法及其获取字节码流的方式,使自定义类加载器编写更加简洁。

2.3 双亲委派机制

在这里插入图片描述
助记:“往上捅”

用一个案例证明双亲委派机制保证了Java代码的安全性。

package java.lang;

public class String {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}


错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:
   public static void main(String[] args)
否则 JavaFX 应用程序类必须扩展javafx.application.Application

双亲委派机制的好处:

  • 避免类的重复加载
  • 保护程序安全,防止核心api被随意篡改。

2.3 类的加载过程

加载(Loading)-> 【验证(Verification)-> 准备(preparation)-> 解析(Resolution)】-> 初始化(Initilization)
--------------------------【这个就是链接过程】

【加载】

  1. 通过一个类的全限定名获取定义此类的二进制字节流
  2. 将这个字节流所定义的静态存储结构转化为方法区的运行时数据结构
  3. 在内存中生成代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

.class文件的来源:

  • 本地系统中
  • 网络获取,典型场景:Web Applet。
  • 从zip包中读取,是从jar、war中读取的基础。
  • 运行时计算生成,使用最多的是动态代理技术。
  • 由其他文件生成,典型场景:jsp应用
  • 从专有的数据库中提取.class文件,比较少见
  • 从加密文件中获取,典型的防止Class文件被反编译的保护措施。

【验证】

  1. 目的在于确保class文件中包含的信息符合当前虚拟机的要求,保证被加载的类的正确性,不会危害虚拟机自身的安全。
  2. 主要包括四种验证:文件格式验证,元数据验证,字节码验证,符号引用验证。

【准备】

  1. 为类变量分配内存并且设置类变量的默认初始值,即零值
  2. 如果是被final修饰的static变量,就已经是一个常量了,常量在编译阶段已经分配值了,准备阶段会显示初始化。
  3. 这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量会随着对象一起分配到Java堆中。

【解析】

  1. 将常量池内的符号应用转换为直接引用的过程。
  2. 事实上,解析操作往往会伴随着JVM在执行完初始化之后再执行。

【初始化】
4. 初始化阶段就是执行类构造器方法 <clinit>()的过程. <clinit>()不同于类的构造器(关联:构造器是虚拟机视角下的<init>()
5. <clinit>()不需要定义,是由javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。 类构造器方法中的指令按照语句在源文件中出现的顺序执行。
6. 若一个类具有父类,JVM会保证子类的<clinit>()执行前,父类的<clinit>()方法已经执行完毕。
7. 虚拟机必须保证一个类的<clinit>()方法在多线程环境下被同步加锁。
8.

public class ClassInitTest {
	static {
		number = 20;
		// 报错:非法的前向引用
		// System.out.println(number);
	}

	// prepare : number = 0;
	// initial : 20 ---> 10
	private static int number = 10; 

	public static void main(String[] args) {
		System.out.println(ClassInitTest.number); // 10
	}
}

2.4 其他

JVM中表示两个class对象是否为同一个类的两个必要条件:

  • 类的完整类名必须一致,包括包名
  • 加载这个类的ClassLoader(指ClassLoader实例对象)必须相同

JVM必须知道一个类型是由启动类加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。 当解析一个类型到另一个类型的引用的时候,JVM需要保证这两个类型的类加载器是相同的。

Java程序对类的使用分为:主动使用和被动使用。
主动使用情况:
1 创建类的实例
2 访问某个类或者接口的静态变量,或者对该静态变量赋值
3 调用类的静态方法
4 反射(例如Class.forName(“xxxx”))
5 初始化一个类的子类
6 Java虚拟机启动时被标明为启动类的类
7 JDK7开始提供的动态语言支持:java.lang.invoke.MethodHandle实例的解析结果REF_getStatciREF-putStaticREF-invokeStatic句柄对应的类没有初始化,那么就需要初始化
除了主动使用的情况,都是被动使用,被动使用的时候不会导致类的初始化。

参考材料

[1] https://www.bilibili.com/video/BV1jJ411t71s?p=5&spm_id_from=pageDriver&vd_source=f4dcb991bbc4da0932ef216329aefb60

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

kafka第三课-可视化工具、生产环境问题总结以及性能优化

一、可视化工具 https://pan.baidu.com/s/1qYifoa4 密码&#xff1a;el4o 下载解压之后&#xff0c;编辑该文件&#xff0c;修改zookeeper地址&#xff0c;也就是kafka注册的zookeeper的地址&#xff0c;如果是zookeeper集群&#xff0c;以逗号分开 vi conf/application.conf 启…

前端vue uni-app仿美团下拉框下拉筛选组件

在前端Web开发中&#xff0c;下拉筛选功能是一种非常常见的交互方式&#xff0c;它可以帮助用户快速选择所需的选项。本文将介绍如何利用Vue.js和uni-app框架来实现一个高效的下拉筛选功能。通过使用这两个强大的前端框架&#xff0c;我们可以轻松地创建具有响应式用户操作的下…

Spring Cloud+Uniapp+企业工程管理系统源码之提高工程项目管理软件的效率

高效的工程项目管理软件不仅能够提高效率还应可以帮你节省成本提升利润 在工程行业中&#xff0c;管理不畅以及不良的项目执行&#xff0c;往往会导致项目延期、成本上升、回款拖后&#xff0c;最终导致项目整体盈利下降。企企管理云业财一体化的项目管理系统&#xff0c;确保…

车道线检测|利用边缘检测的原理对车道线图片进行识别

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 这两个都是博主在学习Linux操作系统过程中的记录&#xff0c;希望对大家的学习有帮助&#xff01; 操作系统Operating Syshttps://blog.csdn.net/yu_cblog/category_12165502.html?spm1001.2014.3001.5482Linux S…

Python应用实例(二)数据可视化(三)

数据可视化&#xff08;三&#xff09; 1.使用Plotly模拟掷骰子1.1 安装Plotly1.2 创建Die类1.3 掷骰子1.4 分析结果1.5 绘制直方图1.6 同时掷两个骰子1.7 同时掷两个面数不同的骰子 1.使用Plotly模拟掷骰子 本节将使用Python包Plotly来生成交互式图表。需要创建在浏览器中显示…

【计算机视觉 | 目标检测 | 图像分割】arxiv 计算机视觉关于目标检测和图像分割的学术速递(7 月 17 日论文合集)

文章目录 一、检测相关(5篇)1.1 TALL: Thumbnail Layout for Deepfake Video Detection1.2 Cloud Detection in Multispectral Satellite Images Using Support Vector Machines With Quantum Kernels1.3 Multimodal Motion Conditioned Diffusion Model for Skeleton-based Vi…

LiveGBS流媒体平台GB/T28181功能-海康NVR摄像机自带物联网卡摄像头注册GB/T28181国标平台看不到设备的时候如何抓包及排查

海康大华宇视华为等硬件NVR摄像机注册到LiveGBS国标平台看不到设备的时候如何抓包及排查 1、设备注册后查看不到1.1、是否是自带物联网卡的摄像头1.2、关闭萤石云1.3、防火墙排查1.4、端口排查1.5、IP地址排查1.6、设备TCP/IP配置排查1.7、设备多网卡排查1.8、设备接入配置参数…

docker-compose自建RustDesk远程控制服务器

github&#xff1a; rustdesk/rustdesk-server: RustDesk Server Program (github.com) 一、创建 docker-compose.yml 文件&#xff0c;复制以下 docker-compose 配置文件内容到文件 version: 3networks:rustdesk-net:external: falseservices:hbbs:container_name: hbbspor…

卷积神经网络识别人脸项目—使用百度飞桨ai计算

卷积神经网络识别人脸项目的详细过程 整个项目需要的准备文件&#xff1a; 下载链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1WEndfi14EhVh-8Vvt62I_w 提取码&#xff1a;7777 链接&#xff1a;https://pan.baidu.com/s/10weqx3r_zbS5gNEq-xGrzg 提取码&#x…

【论文笔记】KDD2019 | KGAT: Knowledge Graph Attention Network for Recommendation

Abstract 为了更好的推荐&#xff0c;不仅要对user-item交互进行建模&#xff0c;还要将关系信息考虑进来 传统方法因子分解机将每个交互都当作一个独立的实例&#xff0c;但是忽略了item之间的关系&#xff08;eg&#xff1a;一部电影的导演也是另一部电影的演员&#xff09…

idea-实现热部署

idea-实现热部署 今天在进行idea 开发时突然发现热部署失败了&#xff0c;每次修改内容都要去restart server一次 这样比较麻烦&#xff0c;故而总结一下idea实现热部署的方法&#xff1a; 步骤一&#xff1a; 选择edit configuration 然后跳出server 的配置&#xff0c;方框…

第一性原理COHP计算在材料科学领域的应用

第一性原理COHP计算在材料科学领域的应用 第一性原理COHP计算是一种基于密度泛函理论&#xff08;DFT&#xff09;的计算方法&#xff0c;用于研究固体材料中的化学键和电子结构相互作用。通过COHP计算&#xff0c;我们可以获得许多有用的数据&#xff0c;并且这些数据在材料科…

NFS 存储(二十八)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、概述 二、应用场景 三、安装 四、启动 五、目录结构 六、命令解析 七、配置 八、客户端访问 总结 前言 今天学习的是NFS 存储&#xff0c;主要是讲 nfs 的概述…

1.Lee Code HTML面试题

如何理解HTML语义化 HTML语义化是指在编写HTML代码时,使用合适的标签和元素来表达文档结构和含义,使得页面内容对搜索引擎和开发者更加友好,并增加代码的可读性。语义化的HTML使得网页在没有样式或样式加载失败时仍然能够保持良好的结构和意义。 问题 2

Kubernetes 使用 helm 部署 NFS Provisioner

文章目录 1. 介绍2. 预备条件3. 部署 nfs4. 部署 NFS subdir external provisioner4.1 集群配置 containerd 代理4.2 配置代理堡垒机通过 kubeconfig 部署 部署 MinIO添加仓库修改可配置项 访问nodepotingress 1. 介绍 NFS subdir external provisioner 使用现有且已配置的NFS…

高级ACL列表应用实验

实验拓扑图&#xff1a; 实验要求&#xff1a; PC1可以telnet R1&#xff0c;但不能ping R1&#xff1b;PC1可以ping R2但不能telnet R2&#xff1b;PC2和PC1相反 1、配置IP让整个网络互通 [PC1]ip route-static 0.0.0.0 0.0.0.0 192.168.1.254 [PC2]ip route-static 0.0.0.…

【VB6|第20期】遍历Excel单元格的四种方法

日期&#xff1a;2023年7月19日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

Linux系统编程(信号处理机制)

文章目录 前言一、中断&#xff0c;异常&#xff0c;信号的区别二、信号在Linux中的标识三、信号处理相关函数四、代码实验总结 前言 本篇文章我们来讲解信号的处理机制&#xff0c;信号处理在Linux操作系统中必不可少&#xff0c;这一点值得大家注意&#xff0c;信号又会与中…

DOM事件

文章目录 1.注册事件&#xff08;绑定事件&#xff09;1.1 注册事件概述1.2 addEventListener 事件监听方式1.3 attachEvent 事件监听方式1.4 注册事件兼容性解决方案 2.删除事件&#xff08;解绑事件&#xff09;2.1 删除事件的方式2.2 删除事件兼容性解决方案 3.DOM 事件流4.…

机器学习实践(2.1)LightGBM分类任务

前言 LightGBM也属于Boosting集成学习模型(还有前面文章的XGBoost)&#xff0c;LightGBM和XGBoost同为机器学习的集大成者。相比越来越流行的深度神经网络&#xff0c;LightGBM和XGBoost能更好的处理表格数据&#xff0c;并具有更强的可解释性&#xff0c;还具有易于调参、输入…