写在前面

最近,一直有小伙伴让我整理下关于JVM的知识,经过十几天的收集与整理,初版算是整理出来了。希望对大家有所帮助。

JDK 是什么?

JDK 是用于支持 Java 程序开发的最小环境。

  1. Java 程序设计语言
  2. Java 虚拟机
  3. Java API类库

JRE 是什么?

JRE 是支持 Java 程序运行的标准环境。

  1. Java SE API 子集
  2. Java 虚拟机

Java历史版本的特性?

Java Version SE 5.0

  • 引入泛型;
  • 增强循环,可以使用迭代方式;
  • 自动装箱与自动拆箱;
  • 类型安全的枚举;
  • 可变参数;
  • 静态引入;
  • 元数据(注解);
  • 引入Instrumentation。

Java Version SE 6

  • 支持脚本语言;
  • 引入JDBC 4.0 API;
  • 引入Java Compiler API;
  • 可插拔注解;
  • 增加对Native PKI(Public Key Infrastructure)、Java GSS(Generic Security Service)、Kerberos和LDAP(Lightweight Directory Access Protocol)的支持;
  • 继承Web Services;
  • 做了很多优化。

Java Version SE 7

  • switch语句块中允许以字符串作为分支条件;
  • 在创建泛型对象时应用类型推断;
  • 在一个语句块中捕获多种异常;
  • 支持动态语言;
  • 支持try-with-resources;
  • 引入Java NIO.2开发包;
  • 数值类型可以用2进制字符串表示,并且可以在字符串表示中添加下划线;
  • 钻石型语法;
  • null值的自动处理。

Java 8

  • 函数式接口
  • Lambda表达式
  • Stream API
  • 接口的增强
  • 时间日期增强API
  • 重复注解与类型注解
  • 默认方法与静态方法
  • Optional 容器类

运行时数据区域包括哪些?

  1. 程序计数器
  2. Java 虚拟机栈
  3. 本地方法栈
  4. Java 堆
  5. 方法区
  6. 运行时常量池
  7. 直接内存

程序计数器(线程私有)

程序计数器(Program Counter Register)是一块较小的内存空间,可以看作是当前线程所执行字节码的行号指示器。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器完成。

由于 Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式实现的。为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各线程之间的计数器互不影响,独立存储。

  1. 如果线程正在执行的是一个 Java 方法,计数器记录的是正在执行的虚拟机字节码指令的地址;
  2. 如果正在执行的是 Native 方法,这个计数器的值为空。

程序计数器是唯一一个没有规定任何 OutOfMemoryError 的区域。

Java 虚拟机栈(线程私有)

Java 虚拟机栈(Java Virtual Machine Stacks)是线程私有的,生命周期与线程相同。
虚拟机栈描述的是 Java 方法执行的内存模型:每个方法被执行的时候都会创建一个栈帧(Stack Frame),存储

  1. 局部变量表
  2. 操作栈
  3. 动态链接
  4. 方法出口

每一个方法被调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

这个区域有两种异常情况:

  1. StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度
  2. OutOfMemoryError:虚拟机栈扩展到无法申请足够的内存时

本地方法栈(线程私有)

虚拟机栈为虚拟机执行 Java 方法(字节码)服务。

本地方法栈(Native Method Stacks)为虚拟机使用到的 Native 方法服务。

Java 堆(线程共享)

Java 堆(Java Heap)是 Java 虚拟机中内存最大的一块。Java 堆在虚拟机启动时创建,被所有线程共享。

作用:存放对象实例。垃圾收集器主要管理的就是 Java 堆。Java 堆在物理上可以不连续,只要逻辑上连续即可。

方法区(线程共享)

方法区(Method Area)被所有线程共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

和 Java 堆一样,不需要连续的内存,可以选择固定的大小,更可以选择不实现垃圾收集。

运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分。保存 Class 文件中的符号引用、翻译出来的直接引用。运行时常量池可以在运行期间将新的常量放入池中。

Java 中对象访问是如何进行的?

Object obj =  new  Object();

对于上述最简单的访问,也会涉及到 Java 栈、Java 堆、方法区这三个最重要内存区域。

Object obj

如果出现在方法体中,则上述代码会反映到 Java 栈的本地变量表中,作为 reference 类型数据出现。

new  Object()

反映到 Java 堆中,形成一块存储了 Object 类型所有对象实例数据值的内存。Java堆中还包含对象类型数据的地址信息,这些类型数据存储在方法区中。

如何判断对象是否“死去”?

  1. 引用计数法
  2. 根搜索算法

什么是引用计数法?

给对象添加一个引用计数器,每当有一个地方引用它,计数器就+1,;当引用失效时,计数器就-1;任何时刻计数器都为0的对象就是不能再被使用的。

引用计数法的缺点?

很难解决对象之间的循环引用问题。

什么是根搜索算法?

通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连(用图论的话来说就是从 GC Roots 到这个对象不可达)时,则证明此对象是不可用的。

Java 的4种引用方式?

在 JDK 1.2 之后,Java 对引用的概念进行了扩充,将引用分为

  1. 强引用 Strong Reference
  2. 软引用 Soft Reference
  3. 弱引用 Weak Reference
  4. 虚引用 Phantom Reference

强引用

Object obj =  new  Object();

代码中普遍存在的,像上述的引用。只要强引用还在,垃圾收集器永远不会回收掉被引用的对象。

软引用

用来描述一些还有用,但并非必须的对象。软引用所关联的对象,有在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围,并进行第二次回收。如果这次回收还是没有足够的内存,才会抛出内存异常。提供了 SoftReference 类实现软引用。

弱引用

描述非必须的对象,强度比软引用更弱一些,被弱引用关联的对象,只能生存到下一次垃圾收集发生前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。提供了 WeakReference 类来实现弱引用。

虚引用

一个对象是否有虚引用,完全不会对其生存时间够成影响,也无法通过虚引用来取得一个对象实例。为一个对象关联虚引用的唯一目的,就是希望在这个对象被收集器回收时,收到一个系统通知。提供了 PhantomReference 类来实现虚引用。

有哪些垃圾收集算法?

  1. 标记-清除算法
  2. 复制算法
  3. 标记-整理算法
  4. 分代收集算法

标记-清除算法(Mark-Sweep)

什么是标记-清除算法?

分为标记和清除两个阶段。首先标记出所有需要回收的对象,在标记完成后统一回收被标记的对象。

有什么缺点?

效率问题:标记和清除过程的效率都不高。

空间问题:标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能导致,程序分配较大对象时无法找到足够的连续内存,不得不提前出发另一次垃圾收集动作。

复制算法(Copying)- 新生代

将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当这一块的内存用完了,就将存活着的对象复制到另一块上面,然后再把已经使用过的内存空间一次清理掉。

优点

复制算法使得每次都是针对其中的一块进行内存回收,内存分配时也不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。

缺点

将内存缩小为原来的一半。在对象存活率较高时,需要执行较多的复制操作,效率会变低。

应用

商业的虚拟机都采用复制算法来回收新生代。因为新生代中的对象容易死亡,所以并不需要按照1:1的比例划分内存空间,而是将内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间。每次使用 Eden 和其中的一块 Survivor。

当回收时,将 Eden 和 Survivor 中还存活的对象一次性拷贝到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 空间。Hotspot 虚拟机默认 Eden 和 Survivor 的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80% + 10%),只有10%的内存是会被“浪费”的。

标记-整理算法(Mark-Compact)-老年代

标记过程仍然与“标记-清除”算法一样,但不是直接对可回收对象进行清理,而是让所有存活的对象向一端移动,然后直接清理掉边界以外的内存。

分代收集算法

根据对象的存活周期,将内存划分为几块。一般是把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点,采用最适当的收集算法。

  • 新生代:每次垃圾收集时会有大批对象死去,只有少量存活,所以选择复制算法,只需要少量存活对象的复制成本就可以完成收集。
  • 老年代:对象存活率高、没有额外空间对它进行分配担保,必须使用“标记-清理”或“标记-整理”算法进行回收。

Minor GC 和 Full GC有什么区别?

Minor GC:新生代 GC,指发生在新生代的垃圾收集动作,因为 Java 对象大多死亡频繁,所以 Minor GC 非常频繁,一般回收速度较快。
Full GC:老年代 GC,也叫 Major GC,速度一般比 Minor GC 慢 10 倍以上。

Java 内存

为什么要将堆内存分区?

对于一个大型的系统,当创建的对象及方法变量比较多时,即堆内存中的对象比较多,如果逐一分析对象是否该回收,效率很低。分区是为了进行模块化管理,管理不同的对象及变量,以提高 JVM 的执行效率。

堆内存分为哪几块?

  1. Young Generation Space 新生区(也称新生代)
  2. Tenure Generation Space养老区(也称旧生代)
  3. Permanent Space 永久存储区

分代收集算法

内存分配有哪些原则?

  1. 对象优先分配在 Eden
  2. 大对象直接进入老年代
  3. 长期存活的对象将进入老年代
  4. 动态对象年龄判定
  5. 空间分配担保

Young Generation Space (采用复制算法)

主要用来存储新创建的对象,内存较小,垃圾回收频繁。这个区又分为三个区域:一个 Eden Space 和两个 Survivor Space。

  • 当对象在堆创建时,将进入年轻代的Eden Space。
  • 垃圾回收器进行垃圾回收时,扫描Eden Space和A Suvivor Space,如果对象仍然存活,则复制到B Suvivor Space,如果B Suvivor Space已经满,则复制 Old Gen
  • 扫描A Suvivor Space时,如果对象已经经过了几次的扫描仍然存活,JVM认为其为一个Old对象,则将其移到Old Gen。
  • 扫描完毕后,JVM将Eden Space和A Suvivor Space清空,然后交换A和B的角色(即下次垃圾回收时会扫描Eden Space和B Suvivor Space。

Tenure Generation Space(采用标记-整理算法)

主要用来存储长时间被引用的对象。它里面存放的是经过几次在 Young Generation Space 进行扫描判断过仍存活的对象,内存较大,垃圾回收频率较小。

Permanent Space

存储不变的类定义、字节码和常量等。

Class文件

Java虚拟机的平台无关性

Class文件的组成?

Class文件是一组以8位字节为基础单位的二进制流,各个数据项目间没有任何分隔符。当遇到8位字节以上空间的数据项时,则会按照高位在前的方式分隔成若干个8位字节进行存储。

魔数与Class文件的版本

每个Class文件的头4个字节称为魔数(Magic Number),它的唯一作用是用于确定这个文件是否为一个能被虚拟机接受的Class文件。OxCAFEBABE。

接下来是Class文件的版本号:第5,6字节是次版本号(Minor Version),第7,8字节是主版本号(Major Version)。

使用JDK 1.7编译输出Class文件,格式代码为:

前四个字节为魔数,次版本号是0x0000,主版本号是0x0033,说明本文件是可以被1.7及以上版本的虚拟机执行的文件。

  • 33:JDK1.7
  • 32:JDK1.6
  • 31:JDK1.5
  • 30:JDK1.4
  • 2F:JDK1.3

类加载器

类加载器的作用是什么?

类加载器实现类的加载动作,同时用于确定一个类。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性。即使两个类来源于同一个Class文件,只要加载它们的类加载器不同,这两个类就不相等。

类加载器有哪些?

  1. 启动类加载器(Bootstrap ClassLoader):使用C++实现(仅限于HotSpot),是虚拟机自身的一部分。负责将存放在\lib目录中的类库加载到虚拟机中。其无法被Java程序直接引用。
  2. 扩展类加载器(Extention ClassLoader)由ExtClassLoader实现,负责加载\lib\ext目录中的所有类库,开发者可以直接使用。
  3. 应用程序类加载器(Application ClassLoader):由APPClassLoader实现。负责加载用户类路径(ClassPath)上所指定的类库。

类加载机制

什么是双亲委派模型?

双亲委派模型(Parents Delegation Model)要求除了顶层的启动类加载器外,其余加载器都应当有自己的父类加载器。类加载器之间的父子关系,通过组合关系复用。
工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有到父加载器反馈自己无法完成这个加载请求(它的搜索范围没有找到所需的类)时,子加载器才会尝试自己去加载。

为什么要使用双亲委派模型,组织类加载器之间的关系?

Java类随着它的类加载器一起具备了一种带优先级的层次关系。比如java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都是委派给启动类加载器进行加载,因此Object类在程序的各个类加载器环境中,都是同一个类。

如果没有使用双亲委派模型,让各个类加载器自己去加载,那么Java类型体系中最基础的行为也得不到保障,应用程序会变得一片混乱。

什么是类加载机制?

Class文件描述的各种信息,都需要加载到虚拟机后才能运行。虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

虚拟机和物理机的区别是什么?

这两种机器都有代码执行的能力,但是:

  • 物理机的执行引擎是直接建立在处理器、硬件、指令集和操作系统层面的。
  • 虚拟机的执行引擎是自己实现的,因此可以自行制定指令集和执行引擎的结构体系,并且能够执行那些不被硬件直接支持的指令集格式。

运行时栈帧结构

栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构, 存储了方法的

  • 局部变量表
  • 操作数栈
  • 动态连接
  • 方法返回地址

每一个方法从调用开始到执行完成的过程,就对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。

Java 方法调用

什么是方法调用?

方法调用唯一的任务是确定被调用方法的版本(调用哪个方法),暂时还不涉及方法内部的具体运行过程。

Java的方法调用,有什么特殊之处?

Class文件的编译过程不包含传统编译的连接步骤,一切方法调用在Class文件里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址。这使得Java有强大的动态扩展能力,但使Java方法的调用过程变得相对复杂,需要在类加载期间甚至到运行时才能确定目标方法的直接引用。

Java虚拟机调用字节码指令有哪些?

  • invokestatic:调用静态方法
  • invokespecial:调用实例构造器方法、私有方法和父类方法
  • invokevirtual:调用所有的虚方法
  • invokeinterface:调用接口方法

虚拟机是如何执行方法里面的字节码指令的?

解释执行(通过解释器执行)
编译执行(通过即时编译器产生本地代码)

解释执行

当主流的虚拟机中都包含了即时编译器后,Class文件中的代码到底会被解释执行还是编译执行,只有虚拟机自己才能准确判断。

Javac编译器完成了程序代码经过词法分析、语法分析到抽象语法树,再遍历语法树生成线性的字节码指令流的过程。因为这一动作是在Java虚拟机之外进行的,而解释器在虚拟机的内部,所以Java程序的编译是半独立的实现。

基于栈的指令集和基于寄存器的指令集

什么是基于栈的指令集?

Java编译器输出的指令流,里面的指令大部分都是零地址指令,它们依赖操作数栈进行工作。

计算“1+1=2”,基于栈的指令集是这样的:

iconst_1
iconst_1
iadd
istore_0

两条iconst_1指令连续地把两个常量1压入栈中,iadd指令把栈顶的两个值出栈相加,把结果放回栈顶,最后istore_0把栈顶的值放到局部变量表的第0个Slot中。

什么是基于寄存器的指令集?

最典型的是x86的地址指令集,依赖寄存器工作。
计算“1+1=2”,基于寄存器的指令集是这样的:

mov eax,  1
add eax,  1

mov指令把EAX寄存器的值设为1,然后add指令再把这个值加1,结果就保存在EAX寄存器里。

基于栈的指令集的优缺点?

优点:

  • 可移植性好:用户程序不会直接用到这些寄存器,由虚拟机自行决定把一些访问最频繁的数据(程序计数器、栈顶缓存)放到寄存器以获取更好的性能。
  • 代码相对紧凑:字节码中每个字节就对应一条指令
  • 编译器实现简单:不需要考虑空间分配问题,所需空间都在栈上操作

缺点:

  • 执行速度稍慢
  • 完成相同功能所需的指令熟练多

频繁的访问栈,意味着频繁的访问内存,相对于处理器,内存才是执行速度的瓶颈。

Javac编译过程分为哪些步骤?

  1. 解析与填充符号表
  2. 插入式注解处理器的注解处理
  3. 分析与字节码生成

什么是即时编译器?

Java程序最初是通过解释器进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁,就会把这些代码认定为“热点代码”(Hot Spot Code)。

为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器成为即时编译器(Just In Time Compiler,JIT编译器)。

解释器和编译器

许多主流的商用虚拟机,都同时包含解释器和编译器。

  • 当程序需要快速启动和执行时,解释器首先发挥作用,省去编译的时间,立即执行。
  • 当程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码,可以提高执行效率。

如果内存资源限制较大(部分嵌入式系统),可以使用解释执行节约内存,反之可以使用编译执行来提升效率。同时编译器的代码还能退回成解释器的代码。

为什么要采用分层编译?

因为即时编译器编译本地代码需要占用程序运行时间,要编译出优化程度更高的代码,所花费的时间越长。

分层编译器有哪些层次?

分层编译根据编译器编译、优化的规模和耗时,划分不同的编译层次,包括:

  • 第0层:程序解释执行,解释器不开启性能监控功能,可出发第1层编译。
  • 第1层:也成为C1编译,将字节码编译为本地代码,进行简单可靠的优化,如有必要加入性能监控的逻辑。
  • 第2层:也成为C2编译,也是将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。

用Client Compiler和Server Compiler将会同时工作。用Client Compiler获取更高的编译速度,用Server Compiler获取更好的编译质量。

编译对象与触发条件

热点代码有哪些?

  • 被多次调用的方法
  • 被多次执行的循环体

如何判断一段代码是不是热点代码?

要知道一段代码是不是热点代码,是不是需要触发即时编译,这个行为称为热点探测。主要有两种方法:

  • 基于采样的热点探测,虚拟机周期性检查各个线程的栈顶,如果发现某个方法经常出现在栈顶,那这个方法就是“热点方法”。实现简单高效,但是很难精确确认一个方法的热度。
  • 基于计数器的热点探测,虚拟机会为每个方法建立计数器,统计方法的执行次数,如果执行次数超过一定的阈值,就认为它是热点方法。

HotSpot虚拟机使用第二种,有两个计数器:

  • 方法调用计数器
  • 回边计数器(判断循环代码)

方法调用计数器统计方法

统计的是一个相对的执行频率,即一段时间内方法被调用的次数。当超过一定的时间限度,如果方法的调用次数仍然不足以让它提交给即时编译器编译,那这个方法的调用计数器就会被减少一半,这个过程称为方法调用计数器的热度衰减,这个时间就被称为半衰周期。

有哪些经典的优化技术(即时编译器)?

  • 语言无关的经典优化技术之一:公共子表达式消除
  • 语言相关的经典优化技术之一:数组范围检查消除
  • 最重要的优化技术之一:方法内联
  • 最前沿的优化技术之一:逃逸分析

公共子表达式消除

普遍应用于各种编译器的经典优化技术,它的含义是:

如果一个表达式E已经被计算过了,并且从先前的计算到现在E中所有变量的值都没有发生变化,那么E的这次出现就成了公共子表达式。没有必要重新计算,直接用结果代替E就可以了。

数组边界检查消除

因为Java会自动检查数组越界,每次数组元素的读写都带有一次隐含的条件判定操作,对于拥有大量数组访问的程序代码,这无疑是一种性能负担。

如果数组访问发生在循环之中,并且使用循环变量来进行数组访问,如果编译器只要通过数据流分析就可以判定循环变量的取值范围永远在数组区间内,那么整个循环中就可以把数组的上下界检查消除掉,可以节省很多次的条件判断操作。

方法内联

内联消除了方法调用的成本,还为其他优化手段建立良好的基础。

编译器在进行内联时,如果是非虚方法,那么直接内联。如果遇到虚方法,则会查询当前程序下是否有多个目标版本可供选择,如果查询结果只有一个版本,那么也可以内联,不过这种内联属于激进优化,需要预留一个逃生门(Guard条件不成立时的Slow Path),称为守护内联。

如果程序的后续执行过程中,虚拟机一直没有加载到会令这个方法的接受者的继承关系发现变化的类,那么内联优化的代码可以一直使用。否则需要抛弃掉已经编译的代码,退回到解释状态执行,或者重新进行编译。

逃逸分析

逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法里面被定义后,它可能被外部方法所引用,这种行为被称为方法逃逸。被外部线程访问到,被称为线程逃逸。

如果对象不会逃逸到方法或线程外,可以做什么优化?

  • 栈上分配:一般对象都是分配在Java堆中的,对于各个线程都是共享和可见的,只要持有这个对象的引用,就可以访问堆中存储的对象数据。但是垃圾回收和整理都会耗时,如果一个对象不会逃逸出方法,可以让这个对象在栈上分配内存,对象所占用的内存空间就可以随着栈帧出栈而销毁。如果能使用栈上分配,那大量的对象会随着方法的结束而自动销毁,垃圾回收的压力会小很多。
  • 同步消除:线程同步本身就是很耗时的过程。如果逃逸分析能确定一个变量不会逃逸出线程,那这个变量的读写肯定就不会有竞争,同步措施就可以消除掉。
  • 标量替换:不创建这个对象,直接创建它的若干个被这个方法使用到的成员变量来替换。

Java与C/C++的编译器对比

  1. 即时编译器运行占用的是用户程序的运行时间,具有很大的时间压力。
  2. Java语言虽然没有virtual关键字,但是使用虚方法的频率远大于C++,所以即时编译器进行优化时难度要远远大于C++的静态优化编译器。
  3. Java语言是可以动态扩展的语言,运行时加载新的类可能改变程序类型的继承关系,使得全局的优化难以进行,因为编译器无法看见程序的全貌,编译器不得不时刻注意并随着类型的变化,而在运行时撤销或重新进行一些优化。
  4. Java语言对象的内存分配是在堆上,只有方法的局部变量才能在栈上分配。C++的对象有多种内存分配方式。

物理机如何处理并发问题?

运算任务,除了需要处理器计算之外,还需要与内存交互,如读取运算数据、存储运算结果等(不能仅靠寄存器来解决)。
计算机的存储设备和处理器的运算速度差了几个数量级,所以不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存(Cache),作为内存与处理器之间的缓冲:将运算需要的数据复制到缓存中,让运算快速运行。当运算结束后再从缓存同步回内存,这样处理器就无需等待缓慢的内存读写了。
基于高速缓存的存储交互很好地解决了处理器与内存的速度矛盾,但是引入了一个新的问题:缓存一致性。在多处理器系统中,每个处理器都有自己的高速缓存,它们又共享同一主内存。当多个处理器的运算任务都涉及同一块主内存时,可能导致各自的缓存数据不一致。
为了解决一致性的问题,需要各个处理器访问缓存时遵循缓存一致性协议。同时为了使得处理器充分被利用,处理器可能会对输出代码进行乱序执行优化。Java虚拟机的即时编译器也有类似的指令重排序优化。

Java 内存模型

什么是Java内存模型?

Java虚拟机的规范,用来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各个平台下都能达到一致的并发效果。

Java内存模型的目标?

定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出这样的底层细节。此处的变量包括实例字段、静态字段和构成数组对象的元素,但是不包括局部变量和方法参数,因为这些是线程私有的,不会被共享,所以不存在竞争问题。

主内存与工作内存

所以的变量都存储在主内存,每条线程还有自己的工作内存,保存了被该线程使用到的变量的主内存副本拷贝。线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,不能直接读写主内存的变量。不同的线程之间也无法直接访问对方工作内存的变量,线程间变量值的传递需要通过主内存。

内存间的交互操作

一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存,Java内存模型定义了8种操作:

原子性、可见性、有序性

  • 原子性:对基本数据类型的访问和读写是具备原子性的。对于更大范围的原子性保证,可以使用字节码指令monitorenter和monitorexit来隐式使用lock和unlock操作。这两个字节码指令反映到Java代码中就是同步块——synchronized关键字。因此synchronized块之间的操作也具有原子性。
  • 可见性:当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取之前从主内存刷新变量值来实现可见性的。volatile的特殊规则保证了新值能够立即同步到主内存,每次使用前立即从主内存刷新。synchronized和final也能实现可见性。final修饰的字段在构造器中一旦被初始化完成,并且构造器没有把this的引用传递出去,那么其他线程中就能看见final字段的值。
  • 有序性:Java程序的有序性可以总结为一句话,如果在本线程内观察,所有的操作都是有序的(线程内表现为串行的语义);如果在一个线程中观察另一个线程,所有的操作都是无序的(指令重排序和工作内存与主内存同步延迟线性)。

volatile

什么是volatile?

关键字volatile是Java虚拟机提供的最轻量级的同步机制。当一个变量被定义成volatile之后,具备两种特性:

  1. 保证此变量对所有线程的可见性。当一条线程修改了这个变量的值,新值对于其他线程是可以立即得知的。而普通变量做不到这一点。
  2. 禁止指令重排序优化。普通变量仅仅能保证在该方法执行过程中,得到正确结果,但是不保证程序代码的执行顺序。

为什么基于volatile变量的运算在并发下不一定是安全的?

volatile变量在各个线程的工作内存,不存在一致性问题(各个线程的工作内存中volatile变量,每次使用前都要刷新到主内存)。但是Java里面的运算并非原子操作,导致volatile变量的运算在并发下一样是不安全的。

为什么使用volatile?

在某些情况下,volatile同步机制的性能要优于锁(synchronized关键字),但是由于虚拟机对锁实行的许多消除和优化,所以并不是很快。

volatile变量读操作的性能消耗与普通变量几乎没有差别,但是写操作则可能慢一些,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

并发与线程

并发与线程的关系?

并发不一定要依赖多线程,PHP中有多进程并发。但是Java里面的并发是多线程的。

什么是线程?

线程是比进程更轻量级的调度执行单位。线程可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I/O),又可以独立调度(线程是CPU调度的最基本单位)。

实现线程有哪些方式?

  • 使用内核线程实现
  • 使用用户线程实现
  • 使用用户线程+轻量级进程混合实现

Java线程的实现

操作系统支持怎样的线程模型,在很大程度上就决定了Java虚拟机的线程是怎样映射的。

Java线程调度

什么是线程调度?

线程调度是系统为线程分配处理器使用权的过程。

线程调度有哪些方法?

  • 协同式线程调度:实现简单,没有线程同步的问题。但是线程执行时间不可控,容易系统崩溃。
  • 抢占式线程调度:每个线程由系统来分配执行时间,不会有线程导致整个进程阻塞的问题。

虽然Java线程调度是系统自动完成的,但是我们可以建议系统给某些线程多分配点时间——设置线程优先级。Java语言有10个级别的线程优先级,优先级越高的线程,越容易被系统选择执行。

但是并不能完全依靠线程优先级。因为Java的线程是被映射到系统的原生线程上,所以线程调度最终还是由操作系统说了算。如Windows中只有7种优先级,所以Java不得不出现几个优先级相同的情况。同时优先级可能会被系统自行改变。Windows系统中存在一个“优先级推进器”,当系统发现一个线程执行特别勤奋,可能会越过线程优先级为它分配执行时间。

线程安全的定义?

当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方法进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。

Java语言操作的共享数据,包括哪些?

  • 不可变
  • 绝对线程安全
  • 相对线程安全
  • 线程兼容
  • 线程对立

不可变

在Java语言里,不可变的对象一定是线程安全的,只要一个不可变的对象被正确构建出来,那其外部的可见状态永远也不会改变,永远也不会在多个线程中处于不一致的状态。

如何实现线程安全?

虚拟机提供了同步和锁机制。

  • 阻塞同步(互斥同步)
  • 非阻塞同步

阻塞同步(互斥同步)

互斥是实现同步的一种手段,临界区、互斥量和信号量都是主要的互斥实现方式。Java中最基本的同步手段就是synchronized关键字,其编译后会在同步块的前后分别形成monitorenter和monitorexit两个字节码指令。这两个字节码都需要一个Reference类型的参数指明要锁定和解锁的对象。如果Java程序中的synchronized明确指定了对象参数,那么这个对象就是Reference;如果没有明确指定,那就根据synchronized修饰的是实例方法还是类方法,去获取对应的对象实例或Class对象作为锁对象。
在执行monitorenter指令时,首先要尝试获取对象的锁。

  • 如果这个对象没有锁定,或者当前线程已经拥有了这个对象的锁,把锁的计数器+1;当执行monitorexit指令时将锁计数器-1。当计数器为0时,锁就被释放了。
  • 如果获取对象失败了,那当前线程就要阻塞等待,知道对象锁被另外一个线程释放为止。

除了synchronized之外,还可以使用java.util.concurrent包中的重入锁(ReentrantLock)来实现同步。ReentrantLock比synchronized增加了高级功能:等待可中断、可实现公平锁、锁可以绑定多个条件。

等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,对处理执行时间非常长的同步块很有用。

公平锁:多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁。synchronized中的锁是非公平的。

非阻塞同步

互斥同步最大的问题,就是进行线程阻塞和唤醒所带来的性能问题,是一种悲观的并发策略。总是认为只要不去做正确的同步措施(加锁),那就肯定会出问题,无论共享数据是否真的会出现竞争,它都要进行加锁、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要被唤醒等操作。

随着硬件指令集的发展,我们可以使用基于冲突检测的乐观并发策略。先进行操作,如果没有其他线程征用数据,那操作就成功了;如果共享数据有征用,产生了冲突,那就再进行其他的补偿措施。这种乐观的并发策略的许多实现不需要线程挂起,所以被称为非阻塞同步。

锁优化是在JDK的那个版本?

JDK1.6的一个重要主题,就是高效并发。HotSpot虚拟机开发团队在这个版本上,实现了各种锁优化:

  • 适应性自旋
  • 锁消除
  • 锁粗化
  • 轻量级锁
  • 偏向锁

为什么要提出自旋锁?

互斥同步对性能最大的影响是阻塞的实现,挂起线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性带来很大压力。同时很多应用共享数据的锁定状态,只会持续很短的一段时间,为了这段时间去挂起和恢复线程并不值得。先不挂起线程,等一会儿。

自旋锁的原理?

如果物理机器有一个以上的处理器,能让两个或以上的线程同时并行执行,让后面请求锁的线程稍等一会,但不放弃处理器的执行时间,看看持有锁的线程是否很快就会释放。为了让线程等待,我们只需让线程执行一个忙循环(自旋)。

自旋的缺点?

自旋等待本身虽然避免了线程切换的开销,但它要占用处理器时间。所以如果锁被占用的时间很短,自旋等待的效果就非常好;如果时间很长,那么自旋的线程只会白白消耗处理器的资源。所以自旋等待的时间要有一定的限度,如果自旋超过了限定的次数仍然没有成功获得锁,那就应该使用传统的方式挂起线程了。

什么是自适应自旋?

自旋的时间不固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。

  • 如果一个锁对象,自旋等待刚刚成功获得锁,并且持有锁的线程正在运行,那么虚拟机认为这次自旋仍然可能成功,进而运行自旋等待更长的时间。
  • 如果对于某个锁,自旋很少成功,那在以后要获取这个锁,可能省略掉自旋过程,以免浪费处理器资源。

有了自适应自旋,随着程序运行和性能监控信息的不断完善,虚拟机对程序锁的状况预测就会越来越准确,虚拟机也会越来越聪明。

锁消除

锁消除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但被检测到不可能存在共享数据竞争的锁进行消除。主要根据逃逸分析。

程序员怎么会在明知道不存在数据竞争的情况下使用同步呢?很多不是程序员自己加入的。

锁粗化

原则上,同步块的作用范围要尽量小。但是如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作在循环体内,频繁地进行互斥同步操作也会导致不必要的性能损耗。

锁粗化就是增大锁的作用域。

轻量级锁

在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

偏向锁

消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。即在无竞争的情况下,把整个同步都消除掉。这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。

参考:《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》

冰河原创PDF

关注 冰河技术 微信公众号。

回复 “并发编程” 领取《深入理解高并发编程(第1版)》PDF文档。

回复 “并发源码” 领取《并发编程核心知识(源码分析篇 第1版)》PDF文档。

回复 ”限流“ 领取《亿级流量下的分布式解决方案》PDF文档。

回复 “设计模式” 领取《深入浅出Java23种设计模式》PDF文档。

回复 “Java8新特性” 领取 《Java8新特性教程》PDF文档。

回复 “分布式存储” 领取《跟冰河学习分布式存储技术》 PDF文档。

回复 “Nginx” 领取《跟冰河学习Nginx技术》PDF文档。

回复 “互联网工程” 领取《跟冰河学习互联网工程技术》PDF文档。

重磅福利

微信搜一搜【冰河技术】微信公众号,关注这个有深度的程序员,每天阅读超硬核技术干货,公众号内回复【PDF】有我准备的一线大厂面试资料和我原创的超硬核PDF技术文档,以及我为大家精心准备的多套简历模板(不断更新中),希望大家都能找到心仪的工作,学习是一条时而郁郁寡欢,时而开怀大笑的路,加油。如果你通过努力成功进入到了心仪的公司,一定不要懈怠放松,职场成长和新技术学习一样,不进则退。如果有幸我们江湖再见!

另外,我开源的各个PDF,后续我都会持续更新和维护,感谢大家长期以来对冰河的支持!!

冰 河CSDN认证博客专家hivestormhadoop
微信搜一搜【冰河技术】微信公众号,关注这个有深度的程序员,每天阅读超硬核技术干货,公众号内回复【PDF】有我准备的一线大厂面试资料和我原创的超硬核PDF技术文档,以及我为大家精心准备的多套简历模板(不断更新中),希望大家都能找到心仪的工作,学习是一条时而郁郁寡欢,时而开怀大笑的路,加油。如果你通过努力成功进入到了心仪的公司,一定不要懈怠放松,职场成长和新技术学习一样,不进则退。如果有幸我们江湖再见!
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 往事如烟 - 老孟

    老孟在我这里印象很深刻,虽然我俩交情并不是很深,但是他乐观的心态和坚持努力的精神给我留下了不可磨灭的印象。老孟是大学同学,他在克亚学院(补招进来的,收费特别高),我在计算机学院&#xff0…...

    2024/4/28 5:56:26
  2. Lambda表达式推导

    Lambda表达式前言一、Lambda简介二、Lambda表达式的优点三、Lambd表达式的推导过程1.实现类方式2.静态内部类3.局部内部类4.匿名内部类5.Lambda表达式6.Lambda表达式进一步的精简(参数类型)7.Lambda表达式进一步的精简(括号)8.Lambda表达式进一步的精简(花括号)四、注意事项五、…...

    2024/4/27 22:29:46
  3. JAVA中HashSet常用API与注意事项

    /*** HashMap注意事项* 底层是数组单向链表,无序集合* LinkedMap是哈希表链表,可保证存储元素有序,继承HashMap,* 双列集合,以键值对形式存在,key\value* key和value的数据类型可以相同也可以不相同* key与value一一对应* key唯一…...

    2024/4/27 2:13:32
  4. 20201118 C++作业批改

    批量下载作业的时候,貌似要弹出什么天空还是什么的JAVA程序才行,而且是用X220这台笔记本...

    2024/4/28 4:50:05
  5. C++控制台代码实现一定的界面效果

    C控制台代码实现一定的界面效果以下为主要的头文件代码&#xff0c;只需要在头文件中添加项然后复制进去即可。//ICUF HEAD_03.H #ifndef ICUF_HEAD_03 #define ICUF_HEAD_03 #define CRT_SECURE_NO_DEPRECATE #include<iostream> #include<conio.h> using namespa…...

    2024/4/28 5:51:57
  6. C++ const深入理解

    如下代码&#xff0c;为什么main会返回0&#xff0c;而不是1呢&#xff1f; int main() {const int a 0xA5A5;int *b (int *)(&a);*b 333;if (*b a) {return 1;}return 0; }如果a是const变量&#xff0c;不能变。但是我们通过a的地址改变了它的值呀。 我翻了《C编程思…...

    2024/4/28 12:40:54
  7. 【Docker】Docker下载与安装

    一、Docker介绍 官网&#xff1a;https://docs.docker.com/get-started/overview/ 二、Docker安装 Docker发展至今&#xff0c;安装方式有多种 Boot2Docker工具安装&#xff08;已经弃用&#xff09; Docker Toolbox &#xff08;适用于win7、win8版本&#xff09; Docker D…...

    2024/4/25 2:36:15
  8. IO优化是怎么做的,使用 SharedPreferences为什么这么卡,mmkv原理是什么

    IO优化是怎么做的&#xff0c;使用 SharedPreferences为什么这么卡&#xff0c;mmkv原理是什么 心理分析&#xff1a;IO优化一直是每个企业必选项&#xff0c;每次闻到都很头疼&#xff0c;面试官想问有没有相关经验&#xff0c;如果有的话&#xff0c;只有两种答案sqlitedata…...

    2024/4/17 18:40:44
  9. 使用proxy仿写jQuery选择器功能

    唯一好处就是省去了每次都要写style的烦琐过程&#xff0c;并将一些元素上一些不必要的像素单位去除了 function $(select,index0) { // 获取元素属性代理器const handler {set(target,key,value){$el.style[key] value},get(target,key){let value target[key]let isNeedP…...

    2024/4/22 2:48:02
  10. PAT甲级真题1052 链表排序(疑难测试点分析)

    链表由一系列的结构体组成&#xff0c;每个结构体中包含一个 Key 值和一个指向下一个结构体的 Next 指针。 现在&#xff0c;给出一个链表&#xff0c;请你按照 Key 值升序的顺序将链表重新排序。 补充 1、本题中可能包含不在链表中的节点&#xff0c;这些节点无需统计&#…...

    2024/4/28 14:26:13
  11. 使用Vavr进行函数式编程(一)

    1. 元组 ( Tuple ) 可以放入多个不同参数的数据类型。弥补Java的函数只能返回一个值的缺陷&#xff08;可以理解为就是一个特殊对象&#xff09;。不易放入多个变量&#xff0c;会导致代码不易阅读。demo //原数组的Tuple2<String, Integer> tuple2 Tuple.of("Hel…...

    2024/4/26 23:40:15
  12. ARM跳转指令

    文章目录跳转指令B指令和BL指令长跳转指令ARM中有两种程序跳转方式&#xff1a;跳转指令&#xff1b;向PC写入目标地址值&#xff1b; 跳转指令 通过跳转指令&#xff0c;可以实现从当前指令向前或者向后32MB的地址空间跳转&#xff08;一般来讲也足够了&#xff0c;基本上没…...

    2024/4/22 10:34:45
  13. Shell——实战

    脚本编程步骤 1、需求分析 根据系统管理的需求&#xff0c;分析脚本要实现的功能、功能实现的层次、实现的命令与语句等 2、命令测试 将要用到的命令逐个进行测试&#xff0c;以决定使用的选项、要设置的变量等 3、脚本编程 将测试好的命令写入脚本文件中&#xff0c;并通过各…...

    2024/4/19 8:47:55
  14. 202006-1 线性分类器

    202006-1 线性分类器 试题编号&#xff1a; 202006-1 试题名称&#xff1a; 线性分类器 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 512.0MB 问题描述&#xff1a; 思路&#xff1a; 对每个直线进行判断时&#xff0c;为了方便&#xff0c;只以第一个点作为标准&#…...

    2024/4/19 6:29:54
  15. Codeforces Round #683 (Div. 2, by Meet IT) E. Xor Tree

    http://codeforces.com/contest/1447/problem/E 题意&#xff1a;给出n个互不相同的数字&#xff0c;对每个i&#xff08;1<i<n&#xff09;找到ai^aj最小的j&#xff08;1<j<n, j ! i&#xff09;连边&#xff0c;求最少删除多少个数能使得这样操作出来得到的是树…...

    2024/4/19 9:53:22
  16. -wise - suffix 后缀

    -wise - suffix 后缀1. -wise [-wise] 以 … 方式&#xff0c;朝…方向&#xff0c;关于&#xff0c;在 … 方面&#xff0c;像 … 一样&#xff0c;如同&#xff0c;位置&#xff0c;样子 forming adjectives and adverbs of manner or respect such as clockwise, otherwise…...

    2024/4/19 5:14:19
  17. file方法整理

    file方法整理 序号方法描述1public String getName() 返回由此抽象路径名表示的文件或目录的名称。2public String getParent()、 返回此抽象路径名的父路径名的路径名字符串&#xff0c;如果此路径名没有指定父目录&#xff0c;则返回 null。3public File getParentFile() 返…...

    2024/4/22 5:14:51
  18. RecyclerView 性能优化

    数据处理和视图加载分离 我们知道&#xff0c;从远端拉取数据肯定是要放在异步的&#xff0c;在我们拉取下来数据之后可能就匆匆把数据丢给了 VH 处理&#xff0c;其实&#xff0c;数据的处理逻辑我们也应该放在异步处理&#xff0c;这样 Adapter 在 notify change 后&#xf…...

    2024/4/19 11:31:08
  19. Ozone ReplicationManager工作原理

    前言 在中心化管理的存储系统中&#xff0c;当系统内的数据出现个别副本损坏的情况时&#xff0c;作为中心控制中心&#xff0c;它需要能够感知系统内的这个情况&#xff0c;并且能够快速的进行副本的拷贝恢复。我们姑且称此类服务为ReplicationManager&#xff0c;或者叫做类似…...

    2024/4/26 10:55:09
  20. Apache ZooKeeper - ZK的ACL权限控制( Access Control List )

    文章目录概述概述 ACL全称为Access Control List&#xff08;访问控制列表&#xff09;&#xff0c;用于控制资源的访问权限,可以控制节点的读写操作,保证数据的安全性 。 ZooKeeper使用ACL来控制对其znode的防问。 Zookeeper ACL 权限设置分为 3 部分组成&#xff0c;分别是…...

    2024/4/19 10:27:50

最新文章

  1. 如此建立网络根文件系统 Mount NFS RootFS

    安静NFS系统服务 sudo apt-get install nfs-kernel-server 创建目录 sudo mkdir /rootfsLee 将buildroot编译的根文件系统解压缩到 sudo tar xvf rootfs.tar -C /rootfsLee/ 添加文件NFS访问路径 sudo vi /etc/exports sudo /etc/exports文件&#xff0c;添加如下一行 …...

    2024/4/28 14:50:13
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. HIS系统是什么?一套前后端分离云HIS系统源码 接口技术RESTful API + WebSocket + WebService

    HIS系统是什么&#xff1f;一套前后端分离云HIS系统源码 接口技术RESTful API WebSocket WebService 医院管理信息系统(全称为Hospital Information System)即HIS系统。 常规模版包括门诊管理、住院管理、药房管理、药库管理、院长查询、电子处方、物资管理、媒体管理等&…...

    2024/4/26 5:05:43
  4. __dirname 在ES模块中的使用

    前言 ECMAScript模块是 JavaScript 的新标准格式。在Node.js中越来越多的库逐渐从从CommonJS转移到ES模块 注&#xff1a;这里是指“真”ES 模块并不是指代码中 Node.js 中使用 import 写法但是实际被 tsc 转成 commonJS 的形式 但是Node.js ES 开发中此前有一个棘手的问题是获…...

    2024/4/26 5:04:45
  5. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/4/28 4:04:40
  6. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/4/28 12:01:04
  7. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/4/27 12:24:35
  8. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/4/27 12:24:46
  9. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/4/28 12:01:03
  10. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/4/28 12:01:03
  11. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/4/28 12:01:03
  12. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/4/27 12:44:49
  13. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/4/27 21:08:20
  14. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/4/28 9:00:42
  15. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/4/27 18:40:35
  16. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/4/28 4:14:21
  17. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/4/27 13:52:15
  18. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/4/27 13:38:13
  19. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/4/28 12:00:58
  20. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/4/28 12:00:58
  21. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/4/27 22:51:49
  22. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/4/28 7:31:46
  23. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/4/28 8:32:05
  24. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/4/27 20:28:35
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57