深入JVM:探索Java虚拟机
文章目录
- 1. JVM简介
- 1.1 定义与核心作用
- 1.2 JVM的跨平台特性
- 2. JVM内部结构深度探索
- 2.1 类加载机制
- 2.1.1 双亲委派模型
- 2.1.2 OSGI框架
- 2.1.3 类加载器分类
- 2.2 JVM运行时数据区
- 2.2.1 程序计数器
- 2.2.2 本地方法栈
- 2.2.3 Java虚拟机栈
- 2.2.4 堆
- 2.2.5 元数据区
- 2.3 JVM内存区域的性能调优实践
- 2.3.1 调优堆内存
- 2.3.2 调优元数据区
- 2.3.3 调优垃圾回收策略
- 3. JVM垃圾回收机制
- 3.1 常见GC收集器
- 3.1.1 串行收集器
- 3.1.2 CMS(并发标记清除)收集器
- 3.1.3 并行收集器
- 3.1.4 G1收集器
- 3.2 垃圾回收算法
- 3.2.1 复制算法
- 3.2.2 标记-清除算法
- 3.2.3 标记-整理算法
- 3.3 JVM内存分区
- 3.3.1 年轻代
- 3.3.2 老年代
- 3.3.3 元数据区
- 4. JVM工具与性能调优
- 4.1 jmap:Java内存映射工具
- 4.1.1 生成堆转储
- 4.1.2 查看堆配置信息
- 4.2 jhat:Java堆分析工具
- 4.2.1 启动jhat
- 4.2.2 查询对象
- 4.3 jstack:Java线程堆栈跟踪工具
- 4.3.1 生成线程堆栈跟踪
- 4.4 jinfo:Java配置信息工具
- 4.4.1 查看JVM标志
- 4.4.2 修改JVM标志
- 4.5 jps:Java进程状态工具
博客思维导图
1. JVM简介
Java虚拟机(JVM)是Java技术的核心组件,它为Java的跨平台特性提供了基础。JVM不仅仅是一个虚拟机,它是一个完整的运行环境,负责加载、验证、编译和执行Java字节码。在本节中,我们将深入探讨JVM的定义、核心作用以及其跨平台的特性。
1.1 定义与核心作用
Java虚拟机是一个虚拟的计算机实例,它使得Java应用程序可以在任何设备或操作系统上运行,只要该设备或操作系统有一个JVM实现。JVM的主要任务是加载.class文件(Java字节码)并执行它们。这些字节码文件是由Java编译器从.java源文件编译而来的。
JVM的核心作用可以归纳为以下几点:
-
加载字节码:JVM负责从文件系统或网络资源加载.class文件。
-
字节码验证:确保加载的字节码是有效的、安全的,并且不会破坏JVM的内部数据结构。
-
即时编译:JVM可以使用即时编译器(JIT)将字节码转换为本地机器代码,以提高执行速度。
-
执行程序:JVM创建并管理所有的程序资源,如线程、内存空间和I/O操作,并执行字节码。
-
提供内置库:JVM提供了Java API,这是一组预编译的类库,可以为Java应用程序提供核心功能。
1.2 JVM的跨平台特性
Java的口号是“一次编写,到处运行”。这得益于Java的跨平台特性,而这一特性的实现则依赖于JVM。
当Java程序被编译时,它被转换为与平台无关的字节码,而不是特定于某个操作系统的机器代码。这意味着,只要一个设备安装了JVM,它就可以运行任何Java应用程序,无论这个程序最初是在哪个平台上编写的。
这种方式的好处是显而易见的:
-
可移植性:Java应用程序可以在任何安装了JVM的设备上运行,无需进行任何修改。
-
安全性:由于Java应用程序在虚拟机上运行,它们与底层操作系统隔离,这为应用程序提供了一个安全的执行环境。
-
性能:尽管Java应用程序在虚拟机上运行,但通过即时编译技术,它们的执行速度可以与本地应用程序相媲美。
-
集成性:Java应用程序可以与其他语言编写的本地应用程序进行交互,这为复杂的应用程序集成提供了便利。
总之,JVM为Java技术提供了坚实的基础,使其成为当今最受欢迎的编程语言之一。通过深入了解JVM,我们可以更好地理解Java的工作原理,从而更有效地编写和优化Java应用程序。
2. JVM内部结构深度探索
Java虚拟机(JVM)是一个复杂的系统,负责执行Java字节码并提供Java应用程序的运行环境。为了更好地理解Java程序的运行机制,我们需要深入探讨JVM的内部结构和其工作原理。
2.1 类加载机制
在Java中,类的加载、链接和初始化是JVM执行Java程序的基础。这些过程确保Java类正确、安全地加载到JVM中。
2.1.1 双亲委派模型
双亲委派模型是Java类加载的核心机制。它确保Java核心库的安全性,防止恶意代码篡改核心类库。
工作原理:
当一个类加载器尝试加载一个类时,它首先会请求其父类加载器来完成这个任务。这个过程会一直递归到启动类加载器;只有当父类加载器不能完成这个任务时,子类加载器才会尝试自己加载这个类。
// 示例代码:自定义类加载器
public class CustomClassLoader extends ClassLoader {@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {// 委派给父类加载器return super.loadClass(name);}
}
代码解释: 上述代码中,我们创建了一个自定义的类加载器。当调用loadClass
方法时,它会首先委派给其父类加载器。
面试题(阿里云):
什么是双亲委派机制?介绍一些运作过程,双亲委派模型的好处;
如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都不愿意干活,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己想办法去完成,这不就是传说中的双亲委派模式。
动作过程
好处
沙箱安全机制:自己写的String.class类不会被加载,这样便可以防止核心API库被随意篡改避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次
2.1.2 OSGI框架
OSGI(Open Service Gateway Initiative)是一个Java模块化框架,它允许应用程序动态地安装、启动、停止和卸载模块。
工作原理:
OSGI框架使用自己的类加载器来加载模块。这允许模块之间有自己的类版本,避免了类版本冲突的问题。
// 示例代码:OSGI BundleActivator
public class MyActivator implements BundleActivator {public void start(BundleContext context) {System.out.println("Module started");}public void stop(BundleContext context) {System.out.println("Module stopped");}
}
代码解释: 上述代码是一个简单的OSGI激活器,它在模块启动和停止时打印消息。
2.1.3 类加载器分类
在JVM中,类加载器被分为三种:
-
启动类加载器(Bootstrap ClassLoader): 负责加载JVM核心类库,如
java.lang.*
。 -
扩展类加载器(Extension ClassLoader): 负责加载Java的扩展库,如
javax.*
。 -
应用类加载器(Application ClassLoader): 负责加载应用程序的类路径、模块路径等。
// 示例代码:获取类加载器
ClassLoader loader = MyClass.class.getClassLoader();
System.out.println(loader);
代码解释: 上述代码获取MyClass
的类加载器并打印它。
2.2 JVM运行时数据区
JVM在执行Java程序时,会使用多个内存区域来存储数据。了解这些区域及其用途对于优化性能和诊断问题至关重要。
2.2.1 程序计数器
程序计数器是一个小的内存区域,它存储了当前线程正在执行的字节码的地址。
工作原理:
当JVM执行一个方法时,程序计数器会指向这个方法的第一条字节码指令。随着字节码指令的执行,程序计数器的值会递增。
// 示例代码:模拟程序计数器
public class ProgramCounterSimulation {public static void main(String[] args) {int counter = 0; // 模拟程序计数器method1();counter += 3; // 假设method1有3条字节码指令method2();counter += 2; // 假设method2有2条字节码指令}public static void method1() {// ...}public static void method2() {// ...}
}
代码解释: 上述代码模拟了程序计数器的工作原理。当调用一个方法时,程序计数器的值会递增,反映了字节码指令的执行。
2.2.2 本地方法栈
本地方法栈是一个内存区域,它存储了Java方法的本地变量、返回地址和其他数据。
工作原理:
当JVM调用一个方法时,它会为这个方法创建一个栈帧并压入本地方法栈。当这个方法返回时,它的栈帧会被弹出。
// 示例代码:模拟本地方法栈
public class LocalMethodStackSimulation {public static void main(String[] args) {method1();method2();}public static void method1() {int localVariable1 = 10; // 存储在本地方法栈中// ...}public static void method2() {String localVariable2 = "Hello"; // 存储在本地方法栈中// ...}
}
代码解释: 上述代码模拟了本地方法栈的工作原理。每个方法的本地变量都存储在本地方法栈中。
2.2.3 Java虚拟机栈
Java虚拟机栈是一个内存区域,它存储了Java方法的操作数栈、局部变量表和其他数据。
工作原理:
与本地方法栈类似,当JVM调用一个方法时,它会为这个方法创建一个栈帧并压
入Java虚拟机栈。但与本地方法栈不同的是,Java虚拟机栈还存储了操作数栈,这是一个用于存储计算过程中的中间结果的栈。
// 示例代码:模拟Java虚拟机栈
public class JVMStackSimulation {public static void main(String[] args) {int result = add(10, 20); // 操作数栈存储10和20,然后存储30(结果)System.out.println(result);}public static int add(int a, int b) {int sum = a + b; // 操作数栈存储a和b的值,然后存储它们的和return sum;}
}
代码解释: 上述代码模拟了Java虚拟机栈的工作原理。add
方法的操作数栈首先存储a
和b
的值,然后存储它们的和。
2.2.4 堆
堆是JVM中的一个重要的内存区域,用于存储对象实例。它被划分为年轻代和老年代,以优化垃圾回收性能。
工作原理:
新创建的对象首先被分配在年轻代。随着时间的推移,存活的对象会从年轻代移动到老年代。垃圾回收主要发生在年轻代,因为大多数对象很快就会变得不可达。
// 示例代码:创建对象
public class HeapSimulation {public static void main(String[] args) {Person person = new Person("Alice", 25); // 对象被分配在堆上}
}class Person {String name;int age;Person(String name, int age) {this.name = name;this.age = age;}
}
代码解释: 上述代码创建了一个Person
对象,这个对象被分配在堆上。
2.2.5 元数据区
元数据区用于存储JVM加载的类的元数据,如类的名称、字段和方法。这个区域不是堆的一部分,它有自己的垃圾回收策略。
工作原理:
当JVM加载一个类时,它会将这个类的元数据存储在元数据区。这个区域是固定大小的,如果它被填满,JVM会触发垃圾回收来回收不再使用的类的元数据。
// 示例代码:加载类
public class MetadataAreaSimulation {public static void main(String[] args) throws ClassNotFoundException {Class<?> clazz = Class.forName("com.example.MyClass"); // 类的元数据被存储在元数据区}
}
代码解释: 上述代码加载了一个类,并将其元数据信息存储在元数据区。
2.3 JVM内存区域的性能调优实践
理解JVM的内存区域对于Java应用程序的性能调优至关重要。通过调整这些区域的大小和参数,我们可以优化应用程序的性能,减少垃圾回收的暂停时间,并提高系统的吞吐量。
2.3.1 调优堆内存
实践案例:
假设一个Web应用程序在高并发情况下经常出现OutOfMemoryError
。通过分析,我们发现这是因为堆内存设置得太小。
解决方案:
增加堆的最大大小。例如,将最大堆大小设置为2GB:
java -Xmx2g -jar my-web-app.jar
建议:
- 使用监控工具(如JVisualVM或JMC)定期检查堆的使用情况。
- 如果应用程序有大量的短暂对象,考虑增加年轻代的大小。
- 如果应用程序有大量的长时间存活的对象,考虑增加老年代的大小。
2.3.2 调优元数据区
实践案例:
一个应用程序在运行时动态生成并加载了大量的类。随着时间的推移,应用程序抛出了OutOfMemoryError: Metaspace
错误。
解决方案:
增加元数据区的大小。例如,将元数据区的最大大小设置为256MB:
java -XX:MaxMetaspaceSize=256m -jar my-dynamic-app.jar
建议:
- 如果应用程序使用了大量的动态代理或CGLIB,考虑增加元数据区的大小。
- 使用
-XX:MetaspaceSize
参数设置元数据区的初始大小,以避免频繁的扩展。
2.3.3 调优垃圾回收策略
实践案例:
一个在线交易应用程序在高并发情况下经常出现长时间的垃圾回收暂停,导致用户体验下降。
解决方案:
切换到低延迟的垃圾回收器,如G1或ZGC:
java -XX:+UseG1GC -jar my-trading-app.jar
建议:
- 根据应用程序的需求选择合适的垃圾回收器。例如,对于低延迟应用程序,G1或ZGC可能是一个好选择;对于高吞吐量应用程序,Parallel GC可能更合适。
- 使用
-XX:GCTimeRatio
和-XX:MaxGCPauseMillis
参数来调整垃圾回收的行为。
3. JVM垃圾回收机制
Java虚拟机(JVM)的垃圾回收(GC)机制是Java内存管理的核心组成部分。它自动回收不再使用的对象,从而释放内存。在本节中,我们将深入探讨JVM的垃圾回收机制,包括常见的GC收集器、垃圾回收算法以及JVM的内存分区。
3.1 常见GC收集器
Java提供了多种GC收集器,每种收集器都有其特定的应用场景和优势。选择合适的收集器可以显著提高应用程序的性能。
3.1.1 串行收集器
串行收集器是最简单的GC收集器,它在单线程环境中工作,并在进行垃圾回收时暂停所有的应用线程。
优势:
- 适用于单线程应用程序。
- 由于没有线程切换的开销,它在单线程环境中通常比其他收集器更快。
缺点:
- 不适用于多线程应用程序,因为它会导致长时间的暂停。
// 启用串行收集器
// JVM参数: -XX:+UseSerialGC
3.1.2 CMS(并发标记清除)收集器
CMS收集器是一种并发收集器,它在标记和清除阶段与应用线程并发执行,从而减少暂停时间。
优势:
- 适用于响应时间要求严格的应用程序。
- 并发执行,减少暂停时间。
缺点:
- 可能导致较高的CPU使用率。
- 由于它不进行压缩,可能导致内存碎片。
// 启用CMS收集器
// JVM参数: -XX:+UseConcMarkSweepGC
3.1.3 并行收集器
并行收集器在多线程环境中工作,它在垃圾回收时使用多个线程。
优势:
- 适用于多线程应用程序。
- 可以充分利用多核CPU。
缺点:
- 在垃圾回收时会暂停所有的应用线程。
// 启用并行收集器
// JVM参数: -XX:+UseParallelGC
3.1.4 G1收集器
G1收集器是一种面向区域的收集器,它将堆分为多个区域,并优先回收垃圾最多的区域。
优势:
- 可以预测暂停时间,从而满足响应时间的要求。
- 高效地利用多核CPU和大量内存。
缺点:
- 可能需要更多的CPU资源。
// 启用G1收集器
// JVM参数: -XX:+UseG1GC
面试题:
GC分哪两种,Minor GC 和Full GC有什么区别?什么时候会触发Full GC?分别采用什么算法?
对象从新生代区域消失的过程,我们称之为 “minor GC”
对象从老年代区域消失的过程,我们称之为 “major GC”
Minor GC
清理整个YouGen的过程,eden的清理,S0\S1的清理都会由于MinorGC Allocation
Failure(YoungGen区内存不足),而触发minorGC
Major GC
OldGen区内存不足,触发Major GC
Full GC
Full GC 是清理整个堆空间—包括年轻代和永久代
Full GC 触发的场景
1)System.gc
2)promotion failed (年代晋升失败,比如eden区的存活对象晋升到S区放不下,又尝试直接晋升到Old区又放不下,那么Promotion Failed,会触发FullGC)
3)CMS的Concurrent-Mode-Failure
由于CMS回收过程中主要分为四步: 1.CMS initial mark 2.CMS Concurrent mark 3.CMS remark 4.CMS Concurrent sweep。在2中gc线程与用户线程同时执行,那么用户线程依旧可能同时产生垃圾, 如果这个垃圾较多无法放入预留的空间就会产生CMS-Mode-Failure, 切换为SerialOld单线程做mark-sweep-compact。
4)新生代晋升的平均大小大于老年代的剩余空间 (为了避免新生代晋升到老年代失败)当使用G1,CMS 时,FullGC发生的时候是Serial+SerialOld。当使用ParalOld时,FullGC发生的时候是 ParallNew +ParallOld.
3.2 垃圾回收算法
垃圾回收算法决定了如何识别和回收不再使用的对象。选择合适的算法可以提高垃圾回收的效率。
3.2.1 复制算法
复制算法将堆分为两个相等的区域,每次只使用其中一个区域。当这个区域被填满时,它会将仍然存活的对象复制到另一个区域,并清空当前区域。
优势:
- 没有内存碎片。
- 只需要处理存活的对象。
缺点:
- 堆的有效容量减半。
// 示例代码:复制算法的简化表示
public void copy() {for (Object obj : fromSpace) {if (isAlive(obj)) {toSpace.add(obj);}}fromSpace.clear();swap(fromSpace, toSpace);
}
代码解释: 上述代码模拟了复制算法的基本工作原理。它首先遍历fromSpace
,将存活的对象复制到toSpace
,然后清空fromSpace
并交换两个空间。
3.2.2 标记-清除算法
标记-清除算法分为两个阶段:标记阶段和清除阶段。在标记阶段,它会标记所有存活的对象;在清除阶段,它会清除所有未被标记的对象。
优势:
- 不需要移动对象。
- 可以回收任何不再使用的对象。
缺点:
- 可能导致内存碎片。
- 清除阶段可能导致较长的暂停时间。
// 示例代码:标记-清除算法的简化表示
public void markAndSweep() {markAllAliveObjects();sweepUnmarkedObjects();
}
代码解释: 上述代码模拟了标记-清除算法的基本工作原理。它首先标记所有存活的对象,然后清除所有未被标记的对象。
3.2.3 标记-整理算法
标记-整理算法是标记-清除算法的一个变种,它在标记和清除阶段之间添加了一个整理阶段。在整理阶段,它会移动所有存活的对象,从而消除内存碎片。
优势:
- 没有内存碎片。
- 可以回收任何不再使用的对象。
缺点:
- 需要移动对象,可能导致较长
的暂停时间。
// 示例代码:标记-整理算法的简化表示
public void markCompact() {markAllAliveObjects();compactAliveObjects();sweepUnmarkedObjects();
}
代码解释: 上述代码模拟了标记-整理算法的基本工作原理。它首先标记所有存活的对象,然后整理存活的对象,最后清除所有未被标记的对象。
3.3 JVM内存分区
JVM将内存分为几个区域,每个区域都有其特定的用途和垃圾回收策略。
3.3.1 年轻代
年轻代是堆的一部分,它包括Eden区和两个Survivor区。大多数新创建的对象首先被分配到Eden区。当Eden区被填满时,存活的对象会被移动到一个Survivor区,而非存活的对象会被回收。
// 示例代码:创建一个新对象
Object obj = new Object();
代码解释: 上述代码创建了一个新对象,这个对象首先被分配到Eden区。
3.3.2 老年代
老年代是堆的另一部分,它用于存储长时间存活的对象。当一个对象在Survivor区存活了足够长的时间,它会被移动到老年代。
// 示例代码:模拟对象的长时间存活
for (int i = 0; i < 10000; i++) {Object obj = new Object();// 使用obj...
}
代码解释: 上述代码创建了大量的对象,并使用它们。这些对象可能会被移动到老年代,因为它们存活了足够长的时间。
3.3.3 元数据区
元数据区用于存储JVM加载的类的元数据信息,如类的名称、字段和方法。这个区域不是堆的一部分,它有自己的垃圾回收策略。
// 示例代码:加载一个类
Class<?> clazz = Class.forName("com.example.MyClass");
代码解释: 上述代码加载了一个类,并将其元数据信息存储在元数据区。
4. JVM工具与性能调优
Java虚拟机(JVM)提供了一系列的工具,帮助开发者监控、诊断和优化应用程序的性能。这些工具为我们提供了深入的洞察,使我们能够更好地理解应用程序在运行时的行为。在本节中,我们将详细探讨这些工具的使用方法和它们在性能调优中的应用。
4.1 jmap:Java内存映射工具
jmap
是一个用于生成堆转储和内存映射的工具。它可以帮助我们诊断内存泄漏和其他内存相关的问题。
4.1.1 生成堆转储
堆转储是JVM内存的快照,它包含了所有的对象及其引用。通过分析堆转储,我们可以识别内存泄漏和优化内存使用。
# 生成堆转储
jmap -dump:format=b,file=heapdump.hprof <pid>
代码解释: 上述命令会为指定的进程ID生成一个名为heapdump.hprof
的堆转储文件。
4.1.2 查看堆配置信息
jmap
还可以显示JVM的堆配置信息,这对于调优堆大小和其他相关参数非常有用。
# 查看堆配置信息
jmap -heap <pid>
代码解释: 上述命令会显示指定进程的堆配置信息,包括堆的大小、使用情况和垃圾回收策略。
4.2 jhat:Java堆分析工具
jhat
是一个用于分析堆转储的工具。它可以解析hprof
文件,并提供一个Web界面来查询数据。
4.2.1 启动jhat
# 使用jhat分析堆转储
jhat heapdump.hprof
代码解释: 上述命令会启动一个Web服务器,默认端口为7000,您可以在浏览器中访问http://localhost:7000
来查看分析结果。
4.2.2 查询对象
jhat
提供了一个简单的OOQL(Object Oriented Query Language)来查询对象。例如,您可以查询所有的String
对象,或者查找特定的对象引用。
4.3 jstack:Java线程堆栈跟踪工具
jstack
是一个用于生成线程堆栈跟踪的工具。它可以帮助我们诊断线程死锁、线程饥饿和其他并发问题。
4.3.1 生成线程堆栈跟踪
# 生成线程堆栈跟踪
jstack <pid>
代码解释: 上述命令会为指定的进程ID生成线程堆栈跟踪。这些跟踪信息可以帮助我们识别线程的状态和它们正在执行的任务。
4.4 jinfo:Java配置信息工具
jinfo
可以显示和调整运行时的JVM配置。这对于调优JVM参数非常有用。
4.4.1 查看JVM标志
# 查看JVM标志
jinfo -flags <pid>
代码解释: 上述命令会显示指定进程的JVM标志,包括堆大小、垃圾回收策略等。
4.4.2 修改JVM标志
# 修改JVM标志
jinfo -flag +PrintGCDetails <pid>
代码解释: 上述命令会为指定进程启用PrintGCDetails
标志,这会导致JVM打印详细的垃圾回收日志。
4.5 jps:Java进程状态工具
jps
是一个显示Java进程信息的工具。它可以列出本地机器上运行的所有Java进程。
# 列出所有Java进程
jps -l
代码解释: 上述命令会列出本地机器上运行的所有Java进程及其主类名。
相关文章:
深入JVM:探索Java虚拟机
文章目录 1. JVM简介1.1 定义与核心作用1.2 JVM的跨平台特性 2. JVM内部结构深度探索2.1 类加载机制2.1.1 双亲委派模型2.1.2 OSGI框架2.1.3 类加载器分类 2.2 JVM运行时数据区2.2.1 程序计数器2.2.2 本地方法栈2.2.3 Java虚拟机栈 2.2.4 堆2.2.5 元数据区 2.3 JVM内存区域的性…...
【计算机网络】 RTT和RTO
文章目录 RTT——往返时延RTO(Retransmission Timeout)——超时重传时间 RTT——往返时延 RTT(Round-Trip Time)是计算机网络中的一个重要的性能指标,表示从发送端发送数据开始,到发送端接收到来自接收端的…...
Zabbix监控组件及流程
Zabbix 由5大组件构成 Zabbix Web、Zabbix Server、Zabbix Proxy、Zabbix Database、Zabbix Agent Zabbix监控系统具体监控系统流程如图: Zabbix Web Zabbix Web是基于PHP语言编写的WEB UI界面,展示Zabbix整个监控平台监控数据、配置信息、方便对整个…...
Type-C协议Ver2.0(学习笔记)
题记 本文以TYPE-C协议Ver2.0版本为基础,以直译为主,同时备注作者学习中遇到的问题与理解,如发现文中描述和协议原文有误,欢迎批评指正,感谢! 1 简介 随着USB接口的持续成功,需要调整USB技术…...
智慧工地:实现作业区域安全管控
智慧工地是围绕工程现场人、机、料、法、环及施工过程中质量、安全、进度、成本等各项数据满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效。 建设工程安全文明施工与质量提升,全方位的监测施工人员、各类器械设备、消防安全隐患,并提前对风险进行预警…...
【Unity插件】实现多人在线游戏——Mirror插件的使用介绍
文章目录 前言导入Mirror插件 简单介绍一、RPC调用二、错误注意 基本使用一、创建场景的网络管理器二、创建一个玩家三、添加玩家初始生成位置四、玩家控制五、同步摄像机六、同步不同角色的名字和颜色修改七、同步动画八、同步子弹方法一方法二 九、聊天功能十、场景同步切换十…...
GeoSOS-FLUS未来土地利用变化情景模拟模型
软件简介 适用场景 GeoSOS-FLUS软件能较好的应用于土地利用变化模拟与未来土地利用情景 的预测和分析中,是进行地理空间模拟、参与空间优化、辅助决策制定的有效工 具。FLUS 模型可直接用于: 城市发展模拟及城市增长边界划定;城市内 部高分…...
IntelliJ IDEA使用_Debug操作
文章目录 版本说明图标和快捷键查看变量计算表达式条件断点多线程调试 版本说明 当前的IntelliJ IDEA 的版本是2021.2.2(下载IntelliJ IDEA) ps:不同版本一些图标和设置位置可能会存在差异,但应该大部分都差不多。 图标和快捷键…...
市场的新宠:4G智能手表
现在人们提到智能手表,健康监测、运动记录、接打电话等定是他不可或缺的功能,而其中通讯功能在绝大数多的智能手表上都是通过蓝牙实现的,需要让手表通过蓝牙连接到手机端来进行。在没有手机的情况下,配置再高的蓝牙智能手表也是“…...
Pytorch Advanced(一) Generative Adversarial Networks
生成对抗神经网络GAN,发挥神经网络的想象力,可以说是十分厉害了 参考 1、AI作家 2、将模糊图变清晰(去雨,去雾,去抖动,去马赛克等),这需要AI具有“想象力”,能脑补情节; 3、进行数…...
Python实操如何去除EXCEL表格中的公式并保留原有的数值
import xlwings as xw app xw.App(visibleTrue, add_bookFalse) # 创建一个不可见的Excel应用程序实例 wb app.books.open(rE:\公式.xlsx) # 打开Excel文件 sheet wb.sheets[DC] # 修改为你的工作表名称 # 假设需要清除公式的范围是A1到B10range_to_clear sheet.range(A…...
MFC串口通信控件MSCOMM32.OCX的安装注册
MSCOMM32.OCX是一个与Microsoft Corporation开发的MSComm控件相关联的文件。MSComm控件是软件应用程序用来与调制解调器、条形码读取器和其他串行设备等设备建立串行通信的通信控件。 下载地址1 https://download.csdn.net/download/m0_60352504/88345092 下载地址2 https://ww…...
27.顺序表练习题目(1)(2023王道数据结构2.2.3前8题)
【这里所有解答都写的是全部代码,目的是让大家能够直接复制上手运行,感受代码的运行过程,而不单单只是写了一个函数】 试题1:(王道2023数据结构综合应用题1) 从顺序表中删除具有最小值的元素(…...
Unity VideoPlayer 指定位置开始播放
如果 source是 videoclip(以下两种方式都可以): _videoPlayer.Play();Debug.Log("time: " _videoPlayer.clip.length);_videoPlayer.time 10; [SerializeField] VideoPlayer videoPlayer;public void SetClipWithTime(VideoClip…...
美团多场景建模的探索与实践
本文介绍了美团到家/站外投放团队在多场景建模技术方向上的探索与实践。基于外部投放的业务背景,本文提出了一种自适应的场景知识迁移和场景聚合技术,解决了在投放中面临外部海量流量带来的场景数量丰富、场景间差异大的问题,取得了明显的效果…...
第11篇:ESP32vscode_platformio_idf框架helloworld点亮LED
第1篇:Arduino与ESP32开发板的安装方法 第2篇:ESP32 helloword第一个程序示范点亮板载LED 第3篇:vscode搭建esp32 arduino开发环境 第4篇:vscodeplatformio搭建esp32 arduino开发环境 第5篇:doit_esp32_devkit_v1使用pmw呼吸灯实验 第6篇:ESP32连接无源喇叭播…...
React中的页面跳转方式详解
在React中,页面跳转通常通过路由来实现。React有多种路由库可供选择,其中最常用的是React Router。React Router提供了几种不同的跳转方式,包括使用组件进行页面跳转、使用组件进行重定向,以及使用编程式导航进行跳转。 使用组件进…...
Golang代码漏洞扫描工具介绍——govulncheck
Golang Golang作为一款近年来最火热的服务端语言之一,深受广大程序员的喜爱,笔者最近也在用,特别是高并发的场景下,golang易用性的优势十分明显,但笔者这次想要介绍的并不是golang本身,而且golang代码的漏洞…...
第31章_瑞萨MCU零基础入门系列教程之WIFI蓝牙模块驱动实验
本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id728461040949 配套资料获取:https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总: ht…...
arkworks工具栈概览
1. 引言 arkworks定位为zkSNARK编程的Rust生态。其开源代码见: https://github.com/arkworks-rs/ arkworks目前已广泛用于大量项目中,如:Aleo、anoma、celo、Espresso、Findora、Manta、Mina、Nimiq、penumbra等等。 参与arkworks开源实现…...
华为云云服务器云耀L实例评测 | 在华为云耀L实例上搭建电商店铺管理系统:一次场景体验
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
sqlserver存储过程报错:当前事务无法提交,而且无法支持写入日志文件的操作。请回滚该事务。
现象: 系统出现异常,手动执行过程提示如上。 问题排查: 1.直接执行的过程事务挂起(排除) 2.重启数据库实例(重启后无效) 3.过程中套用过程,套用的过程中使用事务,因为…...
二刷力扣--字符串
字符串 摘自Python文档-标准库: 在Python中, 字符串是由 Unicode 码位构成的不可变序列。 由于不存在单独的“字符”类型,对字符串做索引操作将产生一个长度为 1 的字符串。 也就是说,对于一个非空字符串 s, s[0] s[0:1]。 不存…...
如何将 OBJ 模型转换和压缩为 GLTF 以与 AWS IoT TwinMaker 配合使用
推荐:使用NSDT场景编辑器快速搭建3D应用场景 概述 在这篇博文中,引用了几种文件扩展名和模型格式。在开始之前,最好了解以下内容: OBJ – 对象文件,一种标准的 3D 图像格式,可以通过各种 3D 图像编辑程序…...
零基础学前端(四)重点讲解 CSS
1. 该篇适用于从零基础学习前端的小白 2. 初学者不懂代码得含义也要坚持模仿逐行敲代码,以身体感悟带动头脑去理解新知识 3. 初学者切忌,不要眼花缭乱,不要四处找其它文档,要坚定一个教授者的方式,将其学通透ÿ…...
类和对象【初始化列表与友元】
全文目录 初始化列表特性 explicit关键字static成员特性 友元友元函数友元类内部类特性 初始化列表 构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。 对象的初始化是在初始化列表进行…...
ActiveRecord::Migration.maintain_test_schema!
测试gem: rspec-rails 问题描述 在使用 rspec-rails 进行测试时,出现了以下错误 ActiveRecord::StatementInvalid: UndefinedFunction: ERROR: function init_id() does not exist这个错误与数据库架构有关。 schema.rb中 create_table "users…...
逆向-beginners之helloworld
#include <stdio.h> int _main() { printf("hello world.\n"); return 0; } // 上面的代码等效于: char *SG3830[] {"hello, world\n"}; int main() { printf("%s", *SG3830); return 0; } #if 0 /* * i…...
如何微调甜甜圈模型——使用示例
Python 中的 Donut 模型可用于从给定图像中提取文本。这在各种场景中都很有用,例如扫描收据。 您可以轻松地。但与人工智能模型一样,您应该根据您的特定需求微调模型。 我编写本教程是因为我没有找到任何资源来准确展示如何使用我的数据集微调 Donut 模型。因此,我必须从其…...
小程序中如何查看指定会员的付款记录
在小程序中,我们可以通过一些简单的步骤来查看指定会员的付款记录。下面是具体的操作流程: 1. 找到指定的会员卡。在管理员后台->会员管理处,找到需要查看付款记录的会员卡。也支持对会员卡按卡号、手机号和等级进行搜索。 2. 查看会员卡…...
长沙企业网站建设多少钱/软文广告示范
一、装饰者模式的内容 装饰(Decorator)模式又名包装(Wrapper)模式[GOF95]。装饰者模式动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择。该模式以对客户端透明的方式扩展对象的功能。利用组…...
小企业官方网站制作/阿里巴巴关键词排名优化
这里只推导逻辑回归的损失公式。 假设函数 hθ(x)11e−θTx(假设函数)h_\theta(x) \frac{1}{1e^{-\theta^Tx}} \tag{假设函数} hθ(x)1e−θTx1(假设函数) 用于二分类 KaTeX parse error: Undefined control sequence: \mbox at position 41: …\theta( x), & \̲m…...
java 快速建站/新闻最新热点
文章目录一、概述二、开发步骤三、相关的类与接口四、操作例子1. 对数据库进行增/删/改时2. 对数据库进行查询时五、事务管理六、JDBC封装七、创建连接池进行优化一、概述 JAVASE规范:指定Java命令开发时基本规则,比如如何创建一个类,如何实…...
网站建设管理 优帮云/企业网络推广的方式有哪些
我们将陆地区域全部染色一般,如果走到边界,那么就说明不可能被包围,否则就会被包围。注意在BFS不能提前返回,否则我们就没有完全染色。 const int dx[] {0, 1, -1, 0}; const int dy[] {1, 0, 0, -1}; class Solution { public…...
seo网站推广优化/中文域名查询官网
2019独角兽企业重金招聘Python工程师标准>>> UDP是一种高速,无连接的数据交换方式,他的特点是,即使没有连接到(也不许要连接)接收方也可以封包发送,就像在一个多人使用的步话机环境中࿰…...
二级建造师考试试题/整站优化的公司
refs: http://blog.chinaunix.net/uid-26404201-id-3334234.html 先看下面的Makefile: #exampleB : $(A)A laterall: echo $(B) 执行make命令,我们发现什么都没输出,我们将第3行的:换成。#exampleB $(A)A laterall: echo $(B) 执行make&#x…...