java JLabel改变大小后如何刷新_到底一行java代码是如何在计算机上执行的

2023-11-15

    不知道你是否思考过,每次我们在IDEA中右键Run Application启动主方法,假如程序运行正常,控制台也打印出了你所要打印的信息,在这个过程中你知道这台计算机上那些硬件及其软件都是以什么样的方式参与到这个过程吗?今天我们就分析梳理下。

案例

1. Jdk的安装目录如下

df4b49ed2d9e5bf75b8149dce4388b1a.png2. 配置环境变量JAVA_HOM、classpath、Path。                                    

dd52fcaf3f26aec8fc36e586883de37c.png

3. 在Idea中编写Test类代码如下                                                                                    

/** * java代码运行流程演示 * @auther yangbp * @date 20201014 */public class Test {    private  boolean flag = true;    void run(){        System.out.println(" 线程开始 ");        while (flag) {        }        System.out.println(" 线程结束 ");    }    public static void main(String[] args) {        Test test = new Test();        new Thread(test::run).start();        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        test.flag = false;    }}

4.运行结果如下

c7b938fd4ba95c263c3835dd20a9e95d.png

思考

(1)JDK、JRE、JVM的区别?

    我们都知道JDK是java development kit 的缩写,意思是java开发工具包,而JRE是 java runtime environment 的缩写,意思是java运行环境,到此应该可以知道,如果我要开发java程序,那必须下载JDK,如果只是运行java 程序则只需安装JRE,但案例中,可以看到JDK的安装目录下包含了JRE。这是一个区别,那还有吗?如下图所示

2cdd12de5ca6b7319bbb79aeeb55eff0.png

6211ba5bf92ce50641ac44b005b57ed9.png

可以看到jdk的bin目录下比jre的bin目录下多了一个javac应用程序,而我们都知道javac是用来把java类编译class(字节码)文件,java命令是来解释运行class文件,最终结果就是将class文件转化成机器码,那它又是咋样做到的,这就用到了JVM(java 虚拟机),从字面意思理解,虚拟机,那就是一个虚拟的计算机,所以它会尽量按照物理机的结构来虚拟出自己的结构。这个jvm就能将class文件转化成机器码供CPU执行。具体可参考官网这张图

b7ccea88e22c3c717fdfd019eb987e14.png(2) 为什么需要配置JAVA_HOME、classpath、Path这些环境变量?

    如果不配置环境变量,那意味着你只能在jdk的bin目录下执行javac命令以及java命令。这样是不是很不方便,重要的是如何理解环境变量,顾名思义,就是一个变量而已,只不过我们可以认为它是全局的,只要配置了,你才可以在你计算机的任何位置执行一些java命令,比如我们配置了环境变量,当使用idea去运行程序时,首先它会在本地找javac应用程序,如果没有就会去Path变量中找。

(3)哈哈,大家肯定对程序运行的结果有些不解,但是造成这个结果的原因只有一个,也不知道和你想的是不是一样,稍后自懂,最终原因肯定是缓存一致性的问题。

分析Test类执行过程

    当我们在idea中右键点击Run Application后,首先会产生一个java.exe进程,这个进程是将Test.java编译成Test.class文件,然后会再生成一个java.exe负责执行Test.class文件。如下图所示

007578114c9ad15b684f7c7f10be4f52.png

cc6618881baf7db9688cb78258c37c35.png

从任务管理器中,我们可以看到,8584这个java进程是负责编译的,而8776这个进程是负责执行class文件的。接下来我们主要分析8776这个进程的分配及执行。

梳理Test类详细执行过程

    假设Test.class是放在linux服务器硬盘上(idea也安装在服务器上),当我们在IDEA中点击Run Application的时候,Linux内核(在linux术语中,将linux操作系统称之为内核)会掌控一切,如下图所示

fd24c51efa9fcf69cc806b6e9cf84449.png

图1

    Linux内核是硬件与软件的桥梁,应用程序只能经过linux内核来调用硬件,硬件的驱动都受到内核的管控。

65d840804cde4f610cf0d0390daca221.png

图2

从硬件角度来看,内存空间由两个部分组成,一个是主存,另一个是SWAP(从磁盘交换的空间),程序运行必须加载到主存中来,而当主存容量不够时,系统会把一部分主存上不用的数据放到磁盘上的SWAP中去,这样就可以腾出主存空间来运行现有程序,当需要用到SWAP中的数据时,再将其加载到主存中来。

从Linux操作系统来看,除了引导系统的BIN区,整个内存空间划分为内核内存(kernel space)和用户内存(user space)。内核内存负责自身使用的内存空间,主要提供给程序调度、内存分配、连接硬件资源等程序逻辑使用。用户内存是提供给各个进程的主要空间,Linux给各个进程提供相同的虚拟内存空间,所有进程都各自拥有4G的内存空间(虚拟内存),这使得进程之间相互独立,互不干扰。实现的方法是采用虚拟内存技术,给每一个进程一定的虚拟内存空间,而只有当虚拟内存实际被使用时,才分配物理内存。如下图所示,对于IA32的Linux来说,一般将0~3G的虚拟内存空间分配作为用户空间,将3~4G的虚拟内存空间划分为内核空间。

c01f62dfc44ef497bfd37a0162254c10.png

图3

    从进程角度来看,进程能直接访问的用户内存(虚拟内存空间)被划分为五个部分:代码区、数据区、堆区、栈区、未使用区。代码区存放应用程序的机器代码,具有只读和固定大小的特点,数据区存放了应用程序中的全局数据、静态数据和一些常量字符串等,其大小也是固定的。堆是运行时程序动态申请的空间,属于程序运行时直接申请、释放的内存资源。栈区用来存放函数的传入参数、临时变量,以及返回地址等数据。未使用区是分配新内存空间的预备区域。

(一)进程与JVM进程

    JVM本质就是一个进程,因此其内存模型也有进程的一般特点,但是JVM又不是一个普通的进程,其在内存模型上有许多崭新的特点,主要原因有两个:(1)JVM将许多本来属于操作系统管理范畴的东西,移植到了JVM内部,目的在于减少系统调用的次数;(2)JAVA NIO,目的在于减少读写IO的系统调用的开销。如下图所示JVM进程与普通进程的内存模型比较

8ae71dfbaef1f3d6d62b659af23a6705.png

图4

    值得注意的是,这个模型并不是JVM内存使用的精确模型,更侧重从操作系统的角度而省略了JVM的内部细节(尽管也很重要)下面从用户内存和内核内存说下JVM进程的内存特点。

(1)用户内存

        上图强调了JVM进程模型的代码区和数据区指的是JVM自身的,而非java程序的。普通进程栈区,在JVM一般仅仅用作线程栈。JVM的堆区和普通进程的差别特别大。

    永久代,本质上是JAVA程序的代码区和数据区,JAVA程序中类(class),也会被加载到整个区域的不同数据结构中去,包括常量池、域、方法数据、方法体、构造函数、以及类中的专用方法、实例初始化、接口初始化等。这个区域对于操作系统来说,是堆的一个部分,而对于java程序来说,这是容纳程序本身及静态资源的空间,使得JVM能够解释执行java程序。

    其次是新生代和老年代,新生代和老年代才是java程序真正使用的堆空间,主要用于内存对象的存储,但是其管理方式和普通进程有本质的区别,普通进程在运行时给内存对象分配空间时,比如C++执行new操作时,会触发一次分配内存空间的系统调用,由操作系统的线程根据对象的大小分配好内存空间后返回;同时,程序释放对象时,比如C++执行delete操作时,也会触发一次系统调用,通知操作系统对象所占用的空间已经可以回收了。

    JVM对内存的使用和一般进程不同,JVM向操作系统申请一整段内存区域(具体大小可在JVM参数调节)作为java程序的堆(分为新生代和老年代);当java程序申请内存空间,比如执行new操作,JVM将在这段空间中按需大小分配给java程序,并且java程序不负责通知JVM何时可以释放这个对象的空间,因为JVM有自己的垃圾回收器。

    JVM的内存管理方式优点显而易见,包括:第一,减少系统调用的次数,JVM在给java程序分配内存空间时不需要操作系统干预,仅仅在java堆大小变化时需要向操纵系统申请内存或通知回收,而普通程序每次内存空间的分配或通知回收都需要系统调用参与;第二,减少内存泄漏,普通进程没有(或者没有及时)通知操作系统内存空间的释放是内存泄漏的重要原因之一,而由JVM统一管理,可以避免程序猿带来的内存泄漏问题。

最后是未使用区,未使用区是分配新内存空间的预备区域。对于普通进程来说,这个区域被用于堆和栈空间的申请与释放,每次堆内存分配都会使用这个区域,因此大小变动频繁,对于JVM进程来说,调整堆大小及线程栈时会使用该区域,而堆大小一般较少调整,因此大小相对稳定。操作系统会动态调整这个区域的大小,并且这个区域通常并没有被实际分配的物理内存,只是允许进程在这个区域申请堆或栈空间。

(2) 内核内存

应用程序通常不直接和内核内存打交道,内核内存由操作系统进行管理和使用;不过随着Linux对性能的关注及改进,一些新特性使得应用程序可以使用内核内存,或者映射到内核空间,JAVA NIO正是在这个背景下产生的,这篇暂不说NIO。

(二)Java 虚拟机(JVM)

(1) JVM生命周期

    * 启动。启动一个java程序时,一个JVM实例就产生了,任何一个拥有public static void main(String[] args)函数的class都可以运行JVM实例。

    * 运行。main()作为该程序初始线程的起点,任何其他线程均由该线程启动

    * 消亡。当程序中的所有非空守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者system.exit来退出。

    一个运行中的java虚拟机有着一个清晰的任务;执行java程序,程序开始执行时他才运行,程序结束时他就停止。你在同一台机器上运行三个程序,就会有三个运行中的java虚拟机。虚拟机总是开始于一个main()方法,这个方法必须是公有、返回void、直接接受一个字符串数组。在程序执行时,你必须给JAVA虚拟机指明这个包下main()方法的类名。main()方法是程序的起点,他被执行的线程初始化为程序的初始线程。程序中其他的线程都由他来启动。

    Java中的线程分为两种:守护线程(daemon) 和 普通线程(non-daemon)。守护线程是java虚拟机自己使用的线程,比如负责垃圾收集的线程就是一个守护线程。当然,你也可以把自己的程序设置为守护线程。包含main()方法的初始线程不是守护线程。

    注意的是只要Java虚拟机中还有普通的线程在执行,JAVA虚拟机就不会停止。如果有足够的权限,你可以调用exit()方法终止程序。

(2)JVM体系结构

    1) 类装载器 (ClassLoader) 用来装载.class文件

    2)执行引擎 (执行字节码,或者执行本地方法)

    3)运行时数据区 (方法区、堆、java栈、PC寄存器、本地方法栈)

(3)JVM运行时数据区

86d606778b1d166543e61faa612759e4.png

图5

3.1 Java 堆(heap)

       * 被所有线程共享的一块内存区域,在虚拟机启动时创建

       * 用来存储对象实例

       * 可以通过-Xmx 和 -Xms控制堆的大小

       * OutOfMemoryError异常:当在堆中没有内存完成实例分配,且堆也无法再扩展时。

    java堆是垃圾回收器管理的主要区域。java堆还可以细分为:新生代(New/Young)、旧生代/年老代(Old/Tenured)。持久代(Permanent)在方法区,不属于Heap。

b30e12b2aa722fa56eb39b25df02b238.png

图6

新生代:新建的对象都有新生代分配内存。常常又被分为Eden区和Survivor区。Eden空间不足时会把存活的对象转移到Survivor。新生代的大小可由-Xmn控制,也可用-XX:SurvivorRatio控制Eden和Survivor的比例。

旧生代:存放经过多次垃圾回收仍然存活的对象。

持久代:存放静态文件,如今Java类、方法等。持久代在方法区,对垃圾回收没有显著影响。

3.2 方法区

    * 线程间共享

    * 用于存储已被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。

    * OutOfMemoryError异常:当方法区无法满足内存的分配需求时

【运行时常量池】

    * 方法区的一部分

    * 用于存放编译期生成的各种字面量与符号引用,如String类型常量就存放在常量池

    * OutOfMemoryError异常:当常量池无法再申请到内存时。

3.3 Java 虚拟机栈(vm stack)

    * 线程私有,生命周期与线程相同 

    * 存储方法的局部变量表(基本类型、对象引用)、操作数栈、动态链接、方法出口等信息。

    * java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧,每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程

    * StackOverFlowError异常:当线程请求的栈深度大于虚拟机所允许的深度

    * OutOfMemoryError异常:如果栈的扩展时无法申请到足够的内存

    JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量、部分的返回结果以及Stack Frame。其他引用类型的对象在JVM栈上仅存放变量名和指向堆上对象实例的首地址

3.4 本地方法栈(Native Method stack)

    与虚拟机栈相似,主要为虚拟机使用到Native方法服务,在HotSpot虚拟机中直接把本地方法栈与虚拟机栈二合一。

3.5 程序计数器(Program Counter Register)

    * 当前线程所执行的字节码的行号指示器

    * 当前线程私有

    * 不会出现OutOfMemoryError情况

3.6 直接内存 (Direct Memory)

  * 直接内存并不是虚拟机运行的一部分,也不是java虚拟机规范中定义的内存区域,但是这部分内存也被频繁使用

  * NIO可以使用Native函数库直接分配堆外内存,堆中的DirectByteBuffer对象作为这块内存的引用进行操作。

  * 大小不受Java堆大小的限制,受本机(服务器)内存限制

  * OutOfMemoryError异常:系统内存不足时。

总结:java对象实例存放在堆中;常量存放在方法区的常量池;虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据存放在方法区;以上区域是所有线程共享的。栈是线程私有的,存放该方法的局部变量表(基本类型、对象引用)、操作数栈、动态链接、方法出口等信息。

    一个java程序对应一个JVM,一个线程对应一个java栈。

(4)JVM执行过程

7c0d4550a574c3841b70ec814c2e8620.png

图7

(四)进程的创建

(1) 基本概念

4.1.1 进程和线程

* 进程是系统资源分配的基本单位,线程是程序独立运行的基本单位

* 线程有时候也被称作小型进程,首先,多个线程之间是可以共享资源的;其次,多个线程之间的切换所花费的代价远远比进程低

4.1.2 轻量级进程

    * 在Linux内核中并不存在线程这个概念,内核对线程并没有设立特别的数据结构,而是与进程一样使用task_struct结构进行描述。

    * 线程在内核中以一个进程的形式而存在的,只不过它比较特殊,它和同类的进程共享某些资源,比如进程地址空间,进程的信号,打开的文件等。这类互相共享资源的进程称之为轻量级进程(Light Weight Process, LWP)

    * 以此策略实现的用户态线程都和内核中一个轻量级进程相对应,多个轻量级进程之间共享资源,从而体现了多线程之间资源共享的特性。同时这些轻量级进程跟普通进程一样由内核进行调度,从而实现了多个进程之间的并发执行。 

4.1.3 POSIX线程库

    POSIX ( Portable  Operating System Interface)便携式操作系统接口,用户级线程和内核中轻量级进程的关联是在符合POSIX标准的线程库中完成的。目前内核支持的线程库为NPTL,即Native Posix Thread library。

4.1.4 线程组

    * POSIX 标准规定在一个多线程的应用程序中,所有线程都必须具有相同的PID。

    * 从线程在内核中的实现可得知,每个线程其实都有自己的PID,为了遵循POSIX标准,Linux引入了线程组的概念,在一个多线程的程序中,所有线程都形成一个线程组。

    * 一个线程组中第一个轻量级进程的PID即为该线程组的PID。通常,每一个线程由主线程创建的,主线程即为调用pthread_create()的线程,因此该线程组中所有线程的PID即为主线程PID。

4.1.5 内核线程

    在内核中有一种特殊的线程,称之为内核线程(kernel thread),内核线程在内核中也是通过task_struct结构体来表示的,内核线程和普通进程一样也是内核调度的实体,但是有以下区别:

    * 内核线程永远都运行在内核态,而进程既可以运行在内核态也可以运行在用户态。

    * 内核线程只能调用内核函数,而普通进程只能通过系统调用才能使用内核函数。

4.1.5 进程描述符

    内核中使用数据结构task_struct来表示进程,该结构即为所谓的进程描述符,它的字段包含了与一个进程相关的所有信息。不仅包含了许多描述进程属性的字段,而且还有一系列指向其他数据结构的指针,其中一部分指向代表进程所拥有的资源的数据结构。

4.1.6 进程地址空间布局图

d39920152092ac4b433baac34e23c223.png

图8

    Linux把进程的用户空间划分为若干个区间,便于管理,这些区间称为虚拟内存区域(简称VMA)。一个进程的用户地址空间主要由mm_struct结构和vm_area_structs结构来描述。mm_struct结构对进程整个用户空间进行描述,m_area_structs结构对用户空间中各个内存区进行描述。进程相关数据结构如下

b436f7f61f163e132c365ce35293081d.png

4.1.7 新建虚拟内存区域

    在内核空间可以通过do_mmap()创建一个新的虚拟内存区域

    在用户空间可以通过mmap()系统调用获取do_mmap()的功能

    值得特别注意的是,这里有个内存映射知识点,何为内存映射?就是把文件从磁盘映射到进程用户空间的一个虚拟内存区域中,对文件的访问转化为对虚拟区的访问。当从这段内存中读数据时,就相当于读磁盘文件中的数据,将数据写入这段内存时,则相当于将数据直接写入磁盘文件。这样就可以在不使用基本I/O操作函数read和write的情况下执行I/O操作。

4.1.6 task_struct 

    在Linux内核中,内核将进程、线程和内核线程一视同仁,即内核使用唯一的数据结构task_struct来分别表示他们;内核使用相同的调度算法对这三者进行调度;并且他们在内核中通过do_fork()分别创建。

    这样处理对内核来说简单方便,内核在统一处理这三者之余并没有失去他们本身所具有的特性。

    对于普通进程来说,进程描述符中每个字段都代表进程的属性

    线程:进程A创建了线程B,则B线程会在内核中对应一个轻量级进程。这个轻量级进程很自然的对应一个进程描述符,只不过B线程的进程描述符中某些代表资源的指针会和A进程中对应的字段指向同一个数据结构,这样就实现了多线程之间的资源共享

    内核线程:由于内核线程只运行在内核态,并且只能由其他内核线程创建,所以内核线程并不需要和普通进程那样的独立地址空间。因此内核线程的进程描述符中的mm指针即为NULL,内核线程是否共享父内核线程的某些资源,则通过向内核线程创建函数kernel_thread()传递参数来决定。

4.1.6 进程API的实现

bfc99fa0335d1657c40e4c5e7ade520e.png

图8

    进程、线程以及内核线程都有对应的系统调用,不过这三者在内核中最终都是由do_fork()进行创建的。这是怎么做到的?咋样区分呢?原因是do_fork()这个函数有很多的参数,根据传参的不同,就可以区分创建进程、线程、内核线程。值得注意的是fork()创建的进程不会共享父进程的任何资源,通常子进程会完全复制父进程的资源,也就是父子进程相对独立。vfork()函数已没有特别的使用之处。clone()通常用于创建轻量级进程。

4.1.7 线程与内核线程的创建

    * 每个用户态的线程在内核中对应一个轻量级进程,两者的关联是通过线程库完成的。

    * 一个新内核线程的创建是通过在现有的内核线程中使用kernel_thread()而创建的,其本质也是向do_fork()提供特定的flags标志而创建的。

    * 由于进程、线程和内核线程使用统一数据结构task_struct来表示,因此他们最终都被do_fork()创建,同时由于task_struct带来了统一性,linux内核也不会为其中某一个设立单独的调度算法,即进行统一的调度管理。

 4.1.8  进程调度

    多任务操作系统分为非抢占式多任务和抢占式多任务,与大多数操作系统一致,linux采用了抢占式多任务模式,意味着进程对CPU的占用时间由操作系统的调度器决定。 

(五)虚拟内存区域与物理内存的转换

        用户态的进程的程序经过编译执行形成进程,进程虽然可以任意访问整个用户空间的内存,但这毕竟属于虚拟地址空间,因此进程最终必须访问到物理内存。

        将虚拟内存和物理内存连接起来的就是分页机制,它在虚拟地址和物理地址之间建立了一种映射关系。

        物理内存管理机制。内核使用page结构体描述一个物理页框,该结构也称为页描述符,页框代表是物理内存的最小单位,内核通过算法来管理物理内存,(1)伙伴算法:负责大块连续物理内存的分配和释放,以页框为基本单位,可以避免外部碎片。(2)slab缓存:负责小块物理内存的分配,并且它也作为一个缓存,主要针对内核中经常分配并释放的对象。(3)per-CPU页框缓存:内核经常请求和释放单个页框,该缓存包含预先分配的页框,用于满足本地CPU发出的单一页框请求。

总结

    了解了这些以后(知识点有点多,不用记,你就只需在脑中好奇它是咋莫一步步被执行的,凡是能感到疑惑的,都有一个知识点或多个在等你探索),到底一行java代码是如何被计算机执行的?我们编译后的class文件放置在硬盘上,当我们在IDEA中右键Run Application的时候,Linux内核会掌控一切,首先Linux会为我们任务创建一个进程,那他是咋样创建的,刚我们说了,Linux最终会调用内核函数do_fork()为我们创建一个进程,用task_struct数据结构来表述这个进程的所有信息,默认会为这个进程分配4G的虚拟内存空间(内核空间1G,用户空间3G),因为刚也说了Linux会把这个进程用户空间分为若干个虚拟区域,用mm_struct结构和vm_area_structs来表示。每个虚拟内存区域Linux内核最终都会调用内核函数do_mmap()来新建虚拟内存区域(VMA),这里会有两个问题,第一个,内存映射,我们都知道内存映射可以避免内核使用基本的I/O读写操作,直接将新建的虚拟空间与硬盘空间对应。但是我们也知道在进程还未执行时,class文件的还是个字节码,到底这个顺序是咋样的?其实它是动态几乎可以认为是并行执行的,这个时候JVM虚拟机也实例化了,它的类加载系统会将硬盘上的class文件通过执行引擎加载到这个JVM进程的虚拟内存空间。第二个,虚拟内存空间与物理内存空间的对应,当进程动态执行的时候,内核会通过请页机制将虚拟内存和物理内存对应起来。整个进程的task_struct数据结构是存储在主存上的,当进程的数据段,代码段有值时,控制器就会开启工作,从内存取指、译指、执行,但此时控制器取到的都是虚拟地址,如何转换呢,如下图所示

1f4a2f817c5d44a6c3a64dabff4434dd.png

图9

        它会通过MMU(内存管理单元,上篇已说过)将虚拟地址给它,然后MMU将对应的物理地址给存储器,转换机制就是分页机制,CPU就会找到主存,将对应的数据指令加载到自己缓存中来,执行即可。大体一行java就是这样再计算机上执行的。

答疑

    回到最开始(3)这个问题上,为什么不打印“线程结束”呢,我在主线程中不是将共享变量flag设为false了吗?首先我们先看下我画的这张图

c9e7438cf1fb9f65463762d191d80b94.png

假如服务器有两个CPU,每个CPU都有俩个核,我们的程序有两个线程(主线程,子线程,这里先不算jvm守护线程),因为每个线程占用cpu核的时间都是由内核对应的算法决定的,假如我们的主线程被CPU1的核1抢先执行,那它将会把flag=true加载到自己的缓存L1,l2,L3中,子线程被CPU1的核2执行,也会将flag=true加载到自己的缓存L1,L2,L3中,主线程创建了子线程,然后主线程又沉睡了1000毫秒,在这1000豪秒的时间内,子线程肯定已经执行很多次了,等主线程醒来将flag的值改为false,那又咋样!因为这时候因为子线程所在cpu中L1,L2已经有了flag的值,所以它不会再从主存加载flag的新值,所以造成了死循环,要想解决很简单,给这个表量设置一个标记,标记当这个变量的值有改变时,所有的CPU核都必须检查更新自己的缓存。而volatile关键字就可以做到,具体原因后面再细讲。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java JLabel改变大小后如何刷新_到底一行java代码是如何在计算机上执行的 的相关文章

  • 基于元数据的数据治理分析功能说明

    数据对于企业来说是非常重要的 因为企业数据需要保证其完整性和准确性 所以需要数据治理 MDM基础数据平台是对各个业务系统的主数据进行治理 而各个业务系统中的业务数据则需要在DAP数据分析平台进行治理 DAP数据分析平台通过与ESB应用集成平
  • 华为od机试 Python 【寻找最大距离】

    题目 小明需要在一个沙地上种下一些树木 但是这片沙地上只有特定的一些位置可以种树 小明想要尽可能地增大树之间的距离来更好地防止沙尘暴 你的任务是帮助他找到这样一个距离 使得在这个距离下他可以种下所有的树 而且这个距离是所有可能距离中最大的
  • MySQL查看锁的sql

    MySQL查看锁的sql 查看数据库状态 会显示加锁的信息等等 show engine innodb status 查看正在执行的线程信息 show full processlist 查看正在锁的表 show open tables whe
  • 利用Nacos服务获取配置逻辑的特点,实现动态配置kafak认证

    我要做什么 实现Nacos动态配置kafka认证信息 使每个微服务读取同一个kafka配置 并生成文件注入到环境变量中 为什么要这么做 首先我们看下 Kafka java接入demo 如图 1 prod client jaas conf文件
  • [GVIM] Increasing or decreasing numbers

    原文链接 https vim fandom com wiki Increasing or decreasing numbers In normal mode typing Ctrl A will increment the next num
  • 怎么用chatgpt润色

    有需要润色的小伙伴 我来帮你们
  • 计算机应用基础本形考任务模块一测验题,国家开放大学《计算机应用基础》考试与答案形考任务模块1-、2—客观题测验答案(59页)-原创力文档...

    模块1 windows 7 操作系统 客观题测验 1 以 为核心组成的微型计算机属于集成电路计算机 A 微处理器 B 电子管 C 晶体管 D 机械 答案是 微处理器 题目2 电子计算机诞生于1946 A 第四台 B 第一台 C 第二台 D
  • Kaptcha配置CaptchaConfig和控制CaptchaController

    前端调用对应的后端接口即可使用验证码 Kaptcha所需依赖 版本号不一
  • python的types模块

    python的types模块 1 types是什么 types模块中包含python中各种常见的数据类型 如IntType 整型 FloatType 浮点型 等等 gt gt gt import types gt gt gt dir typ
  • 华为机试题:求偶数个复数的平均值

    题目描述 由实部和虚部组成 形如 a bi 这样的数 称为复数 通信系统中 通常用32bit数来表示复数 高16bit表示实部 低16bit表示虚部 如整数524295 16进制为0x00080007 所代表的复数 实部为0x0008 虚部
  • Linux系统创建桌面快捷方式,安装idea,配置idea环境

    一 下载Linux版IDEA 使用浏览器打开IDEA官网的链接 https www jetbrains com idea 或https www jetbrains com idea download other html 使用wget命令下
  • python实现电影院仿真(SimPy)

    SimPy Simulating Real World Processes With Python 仿真环境 电影院仿真 目标 减少顾客的平均等待时间 少于10分钟 在开始仿真前 先思考这个仿真过程 顾客在坐下来看电影前需要经过哪些步骤 到
  • Oracle 错误一览表.docx

    ORA 00001 违反唯一约束条件 ORA 00017 请求会话以设置跟踪事件 ORA 00018 超出最大会话数 ORA 00019 超出最大会话许可数 ORA 00020 超出最大进程数 ORA 00021 会话附属于其它某些进程 无
  • centos7下Mercurial (hg)3.9.2版的安装配置及在sts使用mercurial插件clone,pull,commit,push

    Mercurial 已经在centos7的安装源里存在 Mercurial是一种轻量级分布式版本控制系统 采用Python语言实现 易于学习和使用 扩展性强 其是基于GNU General Public License GPL 授权的开源项
  • matlab数据类型和转换

    转自 http hi baidu com xmf6227 blog item 97ca2ddf98f1b61f495403cb html Matlab中有15种基本数据类型 主要是整型 浮点 逻辑 字符 日期和时间 结构数组 单元格数组以及
  • Pytorch面试题整理(2023.09.10)

    1 pytorch如何微调fine tuning 在加载了预训练模型参数之后 需要finetuning 模型 可以使用不同方式finetune 局部微调 加载了模型参数后 只想调节最后几层 其他层不训练 也就是不进行梯度计算 pytorch
  • 10.1-迁移学习

    迁移学习指的就是 假设你手上有一些跟你现在要进行的task没有直接相关的data 那你能不能用这些没有直接相关的data来帮助我们做一些什么事情 比如说 你现在做的是猫跟狗的classifer 那所谓没有什么直接相关的data是什么意思呢
  • win10 wsl 安装 ubuntu 16.04

    背景 因为大多数是在单系统上开发 现在想装win10 ubuntu共存 但双系统切换好麻烦 于是有了在win10里利用wsl装子系统的想法 操作 启动wsl 因为微软商店没有ubuntu16 04 于是到官网下载ubuntu16 04 其他
  • 解决Vue引用Swiper4插件无法重写分页器样式问题

    最近在尝试用nuxtjs来搭建新的站点 但是平时在jquery里面用惯的一些插件一到vue上面引用就各种不顺畅 本文记录一下在用Swiper插件来做轮播图的时候遇到的问题 至于怎么在vue里面引用插件就不累赘了 npm能告诉你 Swiper

随机推荐

  • 一个小时内学习 SQLite 数据库

    SQLite 是一个开源的嵌入式关系数据库 实现自包容 零配置 支持事务的SQL数据库引擎 其特点是高度便携 使用方便 结构紧凑 高效 可靠 与其他数据库管理系统不同 SQLite 的安装和运行非常简单 在大多数情况下 只要确保SQLite
  • 好用的插件介绍-Clear Cache Chrome插件

    clear cache插件是一款用于清理谷歌浏览器的chrome清理缓存插件 该插件支持清理应用程序缓存 缓存 Cookie 下载 文件系统 表单数据 历史 索引数据库 本地存储 插件数据 密码和WebSQL 你只需要在安装了这款插件后在设
  • VSCode中Python代码自动提示

    自己写的模块 VSCode中无法自动提示 可以按下面步骤试试 1 添加模块路径 文件 设置 首选项 搜索autoComplete 点击 在settings json中编辑 添加模块路径 python autoComplete extraPa
  • nrm安装与配置

    1 nrm安装与配置 npm 介绍 nrm npm registry manager 是npm的镜像源管理工具 有时候国外资源太慢 使用这个就可以快速地在 npm 源间切换 参考文章 西北码农 安装 在命令行执行命令 npm install
  • html 邮件乱码怎么办,如何解决html邮件乱码问题

    html邮件乱码的解决办法 1 在mail函数前一行打印message内容 2 将邮件内容保存为html文件后查看 3 设置UTF 8编码 本文操作环境 windows7系统 HTML5版 Dell G3电脑 如何解决html邮件乱码问题
  • Jenkins 持续集成:Linux 系统 两台机器互相免密登录

    背景知识 我们把public key放在远程系统合适的位置 然后从本地开始进行ssh连接 此时 远程的sshd会产生一个随机数并用我们产生的public key进行加密后发给本地 本地会用private key进行解密并把这个随机数发回给远
  • day21

    530 二叉搜索树的最小绝对差 先转换为有序list 再比较差值 501 二叉搜索树中的众数 先转换为有序list 再进行众数统计寻找 236 二叉树的最近公共祖先 后序遍历 再根据返回的值寻找祖先 package algor traini
  • 3d打印,机器人,计算机,3D打印的机器人将教孩子计算机编码!

    原标题 3D打印的机器人将教孩子计算机编码 随着我们的世界变得日益数字化的 越来越多的编码和计算机编程工作如雨后春笋般冒出 需要越来越多的人在编码语言 成为精通 这种先进的计算机知识将更加为下一代更重要 因为2024年 超过100万以上的编
  • Linux 三分钟学会虚拟机与外网和主机互通

    首先准备好一台安装好的虚拟机 字符界面也一样 配置虚拟网卡 添加一张虚拟网卡用来连接主机和虚拟机 通过图中步骤设置好 最后和最后那张图显示一样 确定 右击需要配置网络的虚拟机 单击添加 选中网络适配器 然后单击确定 点击自定义 然后选择刚刚
  • C++ 多态虚函数表(VS2013)

    对于含有虚函数的类 基类或者自身 自身非纯虚函数 的对象 都拥有一个指向虚函数表的指针 占一个指针大小的内存 在类成员变量之前 相当于第一个成员变量 多重继承的时候 几个基类就几个指针 就几个虚函数表 每个类的虚函数表确定了各个方法指向那个
  • Hadoop3.0.3 HDFS 常用shell 命令

    1 启动Hadoop start all sh root elk server sbin start all sh Starting namenodes on elk server 上一次登录 日 11月 24 21 57 43 CST 2
  • 【linux多线程(四)】——线程池的详细解析(含代码)

    目录 什么是线程池 线程池的应用场景 线程池的实现 线程池的代码 C linux线程 壹 初识线程 区分线程和进程 线程创建的基本操作 线程 二 互斥量的详细解析 线程 三 条件变量的详细解析 什么是线程池 线程池是一种线程使用模式 它是将
  • GDB 和 windbg 命令对照(转载)

    From http blog csdn net joeleechj article details 10020501 命令 windbg gdb 附加 attach attach 脱离附加 detach detach 运
  • CSS总结div中的内容垂直居中的六种方法

    一 行高 line height 法如果要垂直居中的只有一行或几个文字 那它的制作最为简单 只要让文字的行高和容器的高度相同即可 比如 p height 30px line height 30px width 100px overflow
  • VMware vSphere中三种磁盘规格(厚置备延迟置零\厚置备置零\Thin Provision

    在VMware vSphere中 不管是以前的5 1版本 或者是现在的6 5版本 创建虚拟机时 在创建磁盘时 都会让选择磁盘的置备类型 如下图所示 分为 1 厚置备延迟置零 2 厚置备置零 3 Thin Provision 精简置备 在创建
  • unity 基本寻径

    一 实现效果 敌人追逐玩家 自动躲避障碍物 二 游戏框架 Plane 平面 是玩家和敌人可以行走的区域 Player 玩家 可以在平面上移动 绕开障碍物 Enemy 敌人 可以追逐玩家 绕开障碍物 障碍物 五个正方体 玩家在移动的过程中和敌
  • java中,在一个类中调用另一个类的属性和方法

    在java当中 在一个类中调用另一个类的情况有多种 可能是调用不同包中的类 也可能是同包不同类 如果调用不同包中的类 需要先导入该包 然后才能调用 这里主要分享一个调用同包中的不同类的属性和方法的操作 比如这里有一个Card类和一个Card
  • ubuntu apt update 报错Err:6 https://download.docker.com/linux/ubuntu jammy InRelease

    目录 尝试清除已存在的软件源信息并重新添加 重新配置ubunut镜像源 我这边用的是阿里云的源 阿里源配置 Ubuntu换阿里云源后更新提示 GPG error缺少公钥解决方法 尝试清除已存在的软件源信息并重新添加 Clear your p
  • oracle.数据的增删改、事务、创建表、修改表、删除表

    一 数据的增删改 1 备份表 01 全表备份 CREATE TABLE 新表名 AS 子查询 将emp表全表备份 CREATE TABLE emp bak AS SELECT FROM emp SELECT FROM emp bak 02
  • java JLabel改变大小后如何刷新_到底一行java代码是如何在计算机上执行的

    不知道你是否思考过 每次我们在IDEA中右键Run Application启动主方法 假如程序运行正常 控制台也打印出了你所要打印的信息 在这个过程中你知道这台计算机上那些硬件及其软件都是以什么样的方式参与到这个过程吗 今天我们就分析梳理下