8. 让java性能提升的JIT深度解剖

2023-11-17


本文是按照自己的理解进行笔记总结,如有不正确的地方,还望大佬多多指点纠正,勿喷。

课程内容:

1、Java的解释执行与JIT(即时编译器)

2、JIT历史发展与分层编译

3、JIT优化技术之方法内联

4、JIT优化技术之锁消除

5、JIT优化技术之逃逸分析

6、JIT优化技术之标量替换与栈上分配

跨语言(语言无关性):JVM只识别字节码(所以跨语言强大),所以JVM其实跟语言是解耦的,也就是没有直接关联,JVM运行不是翻译Java文件,而是识别class文件,这个一般称之为字节码。还有像Groovy 、Kotlin、Scala等等语言,它们其实也是编译成字节码,所以它们也可以在JVM上面跑,这个就是JVM的跨语言特征。Java的跨语言性一定程度上奠定了非常强大的java语言生态圈。

在这里插入图片描述
Java程序在运行的时候,主要就是执行字节码指令,一般这些指令会按照顺序解释执行,这种就是解释执行。

在这里插入图片描述

但是那些被频繁调用的代码,比如调用次数很高或者在 for 循环里的那些代码,如果按照解释执行,效率是非常低的。(这个就是Java以前被C、C++开发者吐槽慢的原因)

以上的这些代码称为热点代码。所以,为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化。

完成这个任务的编译器,就称为即时编译器(Just In Time Compiler),简称 JIT 编译器。

1. C1、C2与Graal编译器

这个编译不是把java变成class,而是将class变成0101这种二进制代码。

在这里插入图片描述
在JDK1.8中 HotSpot 虚拟机中,内置了两个 JIT,分别为 C1 编译器和 C2 编译器。

1.1 C1编译器

C1 编译器是一个简单快速的编译器,主要的关注点在于局部性的优化,适用于执行时间较短或对启动性能有要求的程序,例如,GUI 应用对界面启动速度就有一定要求,C1也被称为 Client Compiler。

C1编译器几乎不会对代码进行优化

1.2 C2编译器

C2 编译器是为长期运行的服务器端应用程序做性能调优的编译器,适用于执行时间较长或对峰值性能有要求的程序。根据各自的适配性,这种即时编译也被称为Server Compiler。

但是C2代码已超级复杂,无人能维护!所以才会开发Java编写的Graal编译器取代C2(JDK10开始)

1.3 分层编译

在 Java7之前,需要根据程序的特性来选择对应的 JIT,虚拟机默认采用解释器和其中一个编译器配合工作。

Java7及以后引入了分层编译,这种方式综合了 C1 的启动性能优势和 C2 的峰值性能优势,当然我们也可以通过参数强制指定虚拟机的即时编译模式。比如我启动的时候就可以用C1,C1比较快嘛。

在 Java8 中,默认开启分层编译。

通过 java -version 命令行可以直接查看到当前系统使用的编译模式(默认分层编译)
在这里插入图片描述
使用“-Xint”参数强制虚拟机运行于只有解释器的编译模式

在这里插入图片描述

使用“-Xcomp”强制虚拟机运行于只有 JIT 的编译模式下

在这里插入图片描述

2. 热点代码

热点代码,就是那些被频繁调用的代码,比如调用次数很高或者在 for 循环里的那些代码。这些再次编译后的机器码会被缓存起来,以备下次使用,但对于那些执行次数很少的代码来说,这种编译动作就纯属浪费。

JVM提供了一个参数“-XX:ReservedCodeCacheSize”,用来限制 CodeCache 的大小。也就是说,JIT 编译后的代码都会放在 CodeCache 里。

如果这个空间不足,JIT 就无法继续编译,编译执行会变成解释执行,性能会降低一个数量级。同时,JIT 编译器会一直尝试去优化代码,从而造成了 CPU 占用上升。

通过 java -XX:+PrintFlagsFinal –version查询:

在这里插入图片描述

3. 热点探测

在 HotSpot 虚拟机中的热点探测是 JIT 优化的条件,热点探测是基于计数器的热点探测,采用这种方法的虚拟机会为每个方法建立计数器统计方法的执行次数,如果执行次数超过一定的阈值就认为它是“热点方法”

虚拟机为每个方法准备了两类计数器:方法调用计数器(Invocation Counter)和回边计数器(Back Edge Counter)。在确定虚拟机运行参数的前提下,这两个计数器都有一个确定的阈值,当计数器超过阈值溢出了,就会触发 JIT 编译。

热点探测技术(以下条件满足一个即可)

  • 方法调用计数器
    服务端模式默认10000
  • 回边计数器(就是的goto line 22,意思就是执行到这个地方回到上面的第22行去。)
    服务端模式默认10700在这里插入图片描述

4. 方法调用计数器

用于统计方法被调用的次数,方法调用计数器的默认阈值在客户端模式下是 1500 次,在服务端模式下是 10000 次(我们用的都是服务端,java –version查询),可通过 -XX: CompileThreshold 来设定

在这里插入图片描述

通过 java -XX:+PrintFlagsFinal –version查询

在这里插入图片描述

5. 回边计数器

用于统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为“回边”(Back Edge),该值用于计算是否触发 C1 编译的阈值,在不开启分层编译的情况下,在服务端模式下是10700。

怎么算的呢!参考以下公式(有兴趣可了解):

回边计数器阈值 =方法调用计数器阈值(CompileThreshold)×(OSR比率(OnStackReplacePercentage)-解释器监控比率(InterpreterProfilePercentage)/100

通过 java -XX:+PrintFlagsFinal –version查询先关参数:
在这里插入图片描述
在这里插入图片描述
其中OnStackReplacePercentage默认值为140,InterpreterProfilePercentage默认值为33,如果都取默认值,那Server模式虚拟机回边计数器的阈值为10700.

回边计数器阈值 =10000×(140-33)=10700

6. 编译优化技术

JIT 编译运用了一些经典的编译优化技术来实现代码的优化,即通过一些例行检查优化,可以智能地编译出运行时的最优性能代码.

6.1 方法内联

方法内联的优化行为就是把目标方法的代码复制到发起调用的方法之中,避免发生真实的方法调用。

  • 热点探测技术触发
  • 方法体大小受限
  • 使用方法内联提升性能

例如以下方法:

private int add1(int x1, int x2, int x3, int x4){
    return add2(x1, x2) + add2(x3, x4);
}
private int add2(int x1, int x2){
    return x1 + x2;
}

最终会被优化为:

//内联后的调用类似于以下方法
private int add(int x1, int x2, int x3, int x4){
    return x1 + x2 + x3 + x4;
}

JVM 会自动识别热点方法,并对它们使用方法内联进行优化。

我们可以通过 -XX:CompileThreshold 来设置热点方法的阈值。

但要强调一点,热点方法不一定会被 JVM 做内联优化,如果这个方法体太大了,JVM 将不执行内联操作。

而方法体的大小阈值,我们也可以通过参数设置来优化:

经常执行的方法,默认情况下,方法体大小小于 325 字节的都会进行内联,我们可以通过 -XX:FreqInlineSize=N 来设置大小值;

在这里插入图片描述

不是经常执行的方法,默认情况下,方法大小小于 35 字节才会进行内联,我们也可以通过 -XX:MaxInlineSize=N 来重置大小值。
在这里插入图片描述

所以我们熟悉的阿里归约之类的对方法体 参数名不要超过几个之类的 因为这里涉及底层的编译有

代码演示

package ding;

/**
 * 方法内联
 * -XX:+PrintCompilation   再控制台打印编译过程信息
 * -XX:+UnlockDiagnosticVMOptions  解锁对JVM进行诊断的选项参数。默认是关闭的,开启后支持一些特定参数对JVM进行诊断
 * -XX:+PrintInlining   将内联方法打印出来
 */
public class CompDemo {
    private int add1(int x1, int x2, int x3, int x4){
        return add2(x1, x2) + add2(x3, x4);
    }
    private int add2(int x1, int x2){
        return x1 + x2;
    }
    //内联后的调用类似于以下方法
    private int add(int x1, int x2, int x3, int x4){
        return x1 + x2 + x3 + x4;
    }

    public static void main(String[] args) {
        CompDemo compDemo = new CompDemo();
        //方法调用计数器的默认阈值10000次,我们循环遍历超过需要阈值
        for (int i = 0; i < 10000; i++){
            compDemo.add1(1,2,3,4);
        }
    }
}

设置 VM 参数:-XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions

-XX:+PrintInlining

-XX:+PrintCompilation //在控制台打印编译过程信息 -XX:+UnlockDiagnosticVMOptions //解锁对JVM进行诊断的选项参数。默认是关闭的,开启后支持一些特定参数对JVM进行诊断 -XX:+PrintInlining //将内联方法打印出来

-XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining

在这里插入图片描述

从打印结果看发生了内联

在这里插入图片描述

什么情况下不会发生呢,我们把for循环里面的数值改的小一点。改成100吧。

在这里插入图片描述
可以看到没有发生内联。
在这里插入图片描述

热点方法的优化可以有效提高系统性能,一般我们可以通过以下几种方式来提高方法内联:

  • 通过设置 JVM 参数来减小热点阈值或增加方法体阈值,以便更多的方法可以进行内联,但这种方法意味着需要占用更多地内存;
  • 在编程中,避免在一个方法中写大量代码,习惯使用小方法体;
  • 尽量使用 final、private、static 关键字修饰方法,编码方法因为继承,会需要额外的类型检查。

7. 锁消除

在非线程安全的情况下,尽量不要使用线程安全容器,比如 StringBuffer。由于 StringBuffer 中的 append 方法被 Synchronized 关键字修饰,会使用到锁,从而导致性能下降。

在这里插入图片描述
但实际上,在以下代码测试中,StringBuffer 和 StringBuilder 的性能基本没什么区别。这是因为在局部方法中创建的对象只能被当前线程访问,无法被其它线程访问,这个变量的读写肯定不会有竞争,这个时候 JIT 编译会对这个对象的方法锁进行锁消除。

下代码测试中,StringBuffer 和 StringBuilder 的性能基本没什么区别。这是因为在局部方法中创建的对象只能被当前线程访问,无法被其它线程访问,这个变量的读写肯定不会有竞争,这个时候 JIT 编译会对这个对象的方法锁进行锁消除。

package ding;

public class UnLock {
    //两种国之间性能有没有很大的差别
    public static void main(String[] args) {
        long timeStart1 = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++){
            BufferString("king","666");//这里是调用方法
        }
        long timeEnd1 = System.currentTimeMillis();
        System.out.println("StringBuffer花费的时间" + (timeEnd1 - timeStart1));


        long timeStart2 = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++){
            BuildString("king","999");//这里是调用方法
        }
        long timeEnd2 = System.currentTimeMillis();
        System.out.println("StringBuild花费的时间" + (timeEnd2 - timeStart2));
    }

    private static String BuildString(String s1, String s2) {
        StringBuilder sd = new StringBuilder();
        sd.append(s1);
        sd.append(s2);
        return sd.toString();
    }

    private static String BufferString(String s1, String s2) {
        StringBuffer sb = new StringBuffer();
        sb.append(s1);
        sb.append(s2);
        return sb.toString();
    }
}

在这里插入图片描述
这个时候发现二者的时间差不多,其实是因为有JIT的锁消除技术。当我们运行的时候,运行一个很大的循环一定会触发JIT,就会热点追踪

我们把锁消除关闭—测试发现性能差别有点大

-XX:+EliminateLocks开启锁消除(jdk1.8默认开启,其它版本未测试)

-XX:-EliminateLocks 关闭锁消除

在这里插入图片描述
锁消除,默认是true

在这里插入图片描述

8. 栈上分配

几乎所有的对象都会被分配到堆中,但是有例外,这个例外就是因为有JIT优化技术,就是逃逸分析技术。
栈是其他的方法访问是访问不到的,栈里面是线程隔离的。

9. 逃逸分析技术

在这里插入图片描述
逃逸分析的原理:分析对象动态作用域,当一个对象在方法中定义后,它可能被外部方法所引用。

比如:调用参数传递到其他方法中,这种称之为方法逃逸。甚至还有可能被外部线程访问到,例如:赋值给其他线程中访问的变量,这个称之为线程逃逸。

从不逃逸到方法逃逸到线程逃逸,称之为对象由低到高的不同逃逸程度。

如果确定一个对象不会逃逸出线程之外,那么让对象在栈上分配内存可以提高JVM的效率。

当然逃逸分析技术属于JIT的优化技术,所以必须要符合热点代码,JIT才会优化,另外对象如果要分配到栈上,需要将对象拆分,这种编译优化就叫做标量替换技术。

说白了,有了热点探测,才有逃逸分析,有了逃逸分析,才有了标量替换,有了标量替换才有了栈上分配。

package ding;

public class EscapeAnalysisTest {
    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 50000000; i++) {
            allocate();

        }
        System.out.println((System.currentTimeMillis() - start) + " ms");
        Thread.sleep(600000);
    }
    static void allocate(){    //逃逸分析(不会逃逸出方法)
        //这个myObject引用没有出去,也没有其他发给发使用
        MyObject myObject = new MyObject(2020,2020.6);

    }
    static class MyObject{
        int a;
        double b;
        MyObject(int a,double b){
            this.a = a;
            this.b = b;
        }
    }
}

运行结果:

在这里插入图片描述

这个时候走的就是栈上分配,他很快的。

我们可以使用-XX:+PrintGC按理来说应该会垃圾回收,毕竟创建了50000000个对象,我们把这个参数加上再运行一下:

在这里插入图片描述

然而事实证明并没有垃圾回收的日志。

为什么没有垃圾回收,因为没有在堆上分配啊,所以没有垃圾回收。

那么栈上分配肯定有逃逸分析,逃逸分析是-XX:-DoEscapeAnalysis,这个参数是默认开启的。那么我们可以尝试关闭,如果关闭了就只能走堆空间分配了。

-XX:-DoEscapeAnalysis -XX:+PrintGC

在这里插入图片描述

我们发现这个时候就出现了垃圾回收,这个时候就是堆上分配了。

可以看到栈上分配还是节省了很多时间。

10. 标量替换

逃逸分析证明一个对象不会被外部访问,如果这个对象可以被拆分的话,当程序真正执行的时候可能不创建这个对象,而直接创建它的成员变量来代替。将对象拆分后,可以分配对象的成员变量在栈或寄存器上,原本的对象就无需分配内存空间了。这种编译优化就叫做标量替换(前提是需要开启逃逸分析)。

堆里面是对象,栈里面的放的是基本数据类型,8大数据类型以及一些引用。要把一个对象放到栈里面就要拆开,所以这个过程就称为标量替换。

标量替换就是说把一个对象进行拆解,拆解到栈或者寄存器上面。栈上分配就是把一个对象放到栈上,标量替换是一个技术点。

package ding;
/*-XX:+DoEscapeAnalysis开启逃逸分析(jdk1.8默认开启)

-XX:-DoEscapeAnalysis 关闭逃逸分析

-XX:+EliminateAllocations开启标量替换(jdk1.8默认开启)

-XX:-EliminateAllocations 关闭标量替换*/
public class VariableDemo {
    public void foo(){
        Teacher teacher = new Teacher();
        teacher.name = "king";
        teacher.age = 18;
    }
    public void fool(){
        String name = "king";
        int age = 18;
    }
}
class Teacher{
    String name;
    String sexType;
    int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSexType() {
        return sexType;
    }

    public void setSexType(String sexType) {
        this.sexType = sexType;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

如上图中foo方法如果使用标量替换的话,那么最后执行的话就是foo1方法的效果。

-XX:+DoEscapeAnalysis开启逃逸分析(jdk1.8默认开启)

-XX:-DoEscapeAnalysis 关闭逃逸分析

-XX:+EliminateAllocations开启标量替换(jdk1.8默认开启)

-XX:-EliminateAllocations 关闭标量替换

如果我们把逃逸分析去掉,而是把标量替换加上,一样可以达到堆上分配的

-XX:-EliminateAllocations -XX:+PrintGC

在这里插入图片描述

总结:

  1. 我们首先判断是不是热点

热点探测技术(以下条件满足一个即可)

  • 方法调用计数器
    服务端模式默认10000次
  • 回边计数器(就是的goto line 22,意思就是执行到这个地方回到上面的第22行去。)
    服务端模式默认10700次
  1. 如果不是则直接堆上分配,如果是热点则判断是否能逃逸
  2. 如果能逃逸则堆上分配,如果不能逃逸判断是否开启了标量替换
  3. 如果没有开启标量替换则堆上分配,如果开启了则栈上分配。

整体总结:

左边是解释器,右边是及时编译器(这个指的是图1)。解释器是逐行解释执行。及时编译器是翻译成1010这种二进制。所以在JIT这块就可以做优化,所以在JIT里面就会有编译器,C1制作编译,几乎不做优化,C2为长期运行的应用做性能调优。所以才会引出热点探测技术,有了探测技术,我才可以做一些优化,比如方法内联,减少栈上的压入。可以做锁消除,没有必要做锁。我们还可以去做逃逸分析、标量替换、栈上分配

方法内联是一种编译技术,就是将一个方法的代码直接嵌入到调用它的代码处,从而避免了方法调用的开销。这样可以提高程序运行效率,因为方法内联能够减少每次方法调用时栈帧的创建和销毁所产生的开销。

举个例子,比如我们有一个方法doSomething,在这个方法中还要调用另一个方法calc,当我们在程序中多次调用doSomething时,每次都需要创建和销毁calc方法所需的栈帧。而如果将calc方法内联到doSomething方法里面,那么就可以避免这些栈帧的创建和销毁开销,从而提高程序的运行效率。

Java中的方法内联可以通过字节码增强技术实现,也可以由JIT编译器跟踪应用程序的行为自动完成。但是方法内联也有缺点,如果开启过多的方法内联,会增加代码量、编译时间和内存使用量,所以需要合理使用。

Java中的锁消除(Lock Elimination)是指编译器在代码执行期间分析程序,如果发现某些同步块或锁机制对于实际业务逻辑并没有意义,可以将其消除掉。这样做可以减少无谓的锁开销、提升代码运行效率和性能。

锁消除有以下两种方式:

1. 基于程序分析:根据代码的流程,分析是否存在竞争情况,如果不存在或者轻微,则可以通过更改程序来消除锁。

2. 基于逃逸分析:在编译期间进行逃逸分析,判断对象是否会被其他线程访问,如果不会,那就可以消除该对象相关的锁。

锁消除的优点是可以减少锁带来的性能瓶颈以及排查使用锁所引发的安全问题。但是,在一些复杂场景下,锁消除可能会带来意想不到的后果,比如导致多线程数据竞争等情况,因此需要根据具体情况进行选择和应用。

总之,锁消除是一个重要的JVM优化技术,它可以避免过度的同步操作对程序性能造成的负面影响,提高代码的运行效率和性能。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

8. 让java性能提升的JIT深度解剖 的相关文章

  • 使用 Java 的 Apache Http 摘要身份验证

    我目前正在开发一个 Java 项目 但无法使 http 摘要身份验证正常工作 我尝试使用 Apache 网站 但没有帮助 我有一个需要 HTTP 摘要身份验证的网站 DefaultHttpClient httpclient new Defa
  • TreeMap 删除所有大于某个键的键

    在项目中 我需要删除键值大于某个键的所有对象 键类型为Date 如果重要的话 据我所知TreeMapJava中实现的是红黑树 它是一种二叉搜索树 所以我应该得到O n 删除子树时 但除了制作尾部视图并一一删除之外 我找不到任何方法可以做到这
  • 如何在 Java 中向时间戳添加/减去时区偏移量?

    我正在使用 JDK 8 并且玩过ZonedDateTime and Timestamp很多 但我仍然无法解决我面临的问题 假设我得到了格式化的Timestamp在格林威治标准时间 UTC 我的服务器位于某处 假设它设置为Asia Calcu
  • 从 MATLAB 调用 Java?

    我想要Matlab程序调用java文件 最好有一个例子 需要考虑三种情况 Java 内置库 也就是说 任何描述的here http docs oracle com javase 6 docs api 这些项目可以直接调用 例如 map ja
  • 将巨大的模式编译成Java

    有两个主要工具提供了将 XSD 模式编译为 Java 的方法 xmlbeans 和 JAXB 问题是 XSD 模式确实很大 30MB 的 XML 文件 大部分模式在我的项目中没有使用 所以我可以注释掉大部分代码 但这不是一个好的解决方案 目
  • java inputstream 打印控制台内容

    sock new Socket www google com 80 out new BufferedOutputStream sock getOutputStream in new BufferedInputStream sock getI
  • 在 Java 中如何找出哪个对象打开了文件?

    我需要找出答案哪个对象在我的 Java 应用程序中打开了一个文件 这是为了调试 因此欢迎使用工具或实用程序 如果发现哪个对象太具体了 这class也会很有帮助 这可能很棘手 您可以从使用分析器开始 例如VisualVM http visua
  • 将非 Android 项目添加到 Android 项目

    我在 Eclipse 中有三个项目 Base Server 和 AndroidClient Base和Server是Java 1 7项目 而AndroidClient显然是一个android项目 基础项目具有在服务器和 Android 客户
  • Android 无法解析日期异常

    当尝试解析发送到我的 Android 客户端的日期字符串时 我得到一个无法解析的日期 这是例外 java text ParseException 无法解析的日期 2018 09 18T00 00 00Z 位于 偏移量 19 在 java t
  • 如何在java中将日期格式从YYMMDD更改为YYYY-MM-DD? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我从机器可读代码中获取日期格式为 YYMMDD 如何将其更改为 YYYY MM DD 例如我收到 871223 YYMMDD 我想把它改成
  • 如何仅从 Firestore 获取最新更新的数据?

    在 Firestore 上发现任何更改时始终获取整个文档 如何只获取最近更新的数据 这是我的数据 我需要在第一次加载时在聊天中按对象顺序 例如 2018 09 17 30 40 msg和sendby 并且如果数据更新则仅获取新的msg和se
  • 从jar中获取资源

    我有包含文件的 jar myJar res endingRule txt myJar wordcalculator merger Marge class 在 Marge java 中我有代码 private static final Str
  • 提高 PostgreSQL 1 亿数据左连接查询性能

    我在用Postgresql 9 2 version Windows 7 64 bit RAM 6GB 这是一个Java企业项目 我必须在我的页面中显示订单相关信息 有三个表通过左连接连接在一起 Tables TV HD 389772 行 T
  • Java继承,扩展类如何影响实际类

    我正在查看 Sun 认证学习指南 其中有一段描述了最终修饰符 它说 如果程序员可以自由地扩展我们所知的 String 类文明 它可能会崩溃 他什么意思 如果可以扩展 String 类 我是否不会有一个名为 MyString 的类继承所有 S
  • 不可变的最终变量应该始终是静态的吗? [复制]

    这个问题在这里已经有答案了 在java中 如果一个变量是不可变的并且是final的 那么它应该是一个静态类变量吗 我问这个问题是因为每次类的实例使用它时创建一个新对象似乎很浪费 因为无论如何它总是相同的 Example 每次调用方法时都会创
  • Spring @Cacheable 和 @Async 注解

    我需要缓存一些异步计算的结果 具体来说 为了克服这个问题 我尝试使用 Spring 4 3 缓存和异步计算功能 作为示例 我们采用以下代码 Service class AsyncService Async Cacheable users C
  • 将 JavaFX FXML 对象分组在一起

    非常具有描述性和信息性的答案将从我这里获得价值 50 声望的赏金 我正在 JavaFX 中开发一个应用程序 对于视图 我使用 FXML
  • 将 JScrollPane 添加到 JFrame

    我有一个关于向 Java 框架添加组件的问题 我有一个带有两个按钮的 JPanel 和一个添加了 JTable 的 JScrollPane 我想将这两个添加到 JFrame 中 我可以将 JPanel 添加到 JFrame 或将 JScro
  • Java/Python 中的快速 IPC/Socket 通信

    我的应用程序中需要两个进程 Java 和 Python 进行通信 我注意到套接字通信占用了 93 的运行时间 为什么通讯这么慢 我应该寻找套接字通信的替代方案还是可以使其更快 更新 我发现了一个简单的修复方法 由于某些未知原因 缓冲输出流似
  • MiniDFSCluster UnsatisfiedLinkError org.apache.hadoop.io.nativeio.NativeIO$Windows.access0

    做时 new MiniDFSCluster Builder config build 我得到这个异常 java lang UnsatisfiedLinkError org apache hadoop io nativeio NativeIO

随机推荐

  • flutter doctor --android-licenses报错解决方案

    C Users 32148 gt flutter doctor android licenses Flutter assets will be downloaded from https storage flutter io cn Make
  • 小米手环nfc门卡摸拟成功后不能开门_如何使用小米手环5 NFC版进行门卡模拟(如公司门禁卡、小区门禁卡、学校门禁卡等)?...

    由于本人最近购入了小米手环5 NFC版 所以对小米手环模拟门禁卡比较清楚一点 说一下用该手环模拟门禁的方法吧 我本人模拟的是学校公寓的门禁卡 不过学校的门禁卡是加密卡 可能操作起来稍微比不加密的门禁卡麻烦一点 因为不加密的门禁卡直接就可以模
  • PLSQL之动态SQL与异常

    1 动态 SQL 动态 SQL 是指在PL SQL程序执行时生成的 SQL 语句 编译程序对动态 SQL 不做处理 而是在程序运行时动态构造语句 对语句进行语法分析并执行 DDL 语句命令和会话控制语句不能在 PL SQL 中直接使用 但是
  • 微信公众号-测试号

    最近碰到了一个H5的公众号项目 需要openid来判断用户是否存在 视乎好多年都没碰这玩意了 完全忘记了 挨着看文档 一路各种坑 好不容易用测试号把本地测试环境调通了 环境不同可能使用的方法方式都不一样 微信测试号 需要微信扫码登陆 1 获
  • unity图片相似度识别

    public static SimilarPhoto Instance
  • 2022最新快捷键大全

    一 常用快捷键 ctrl c v 复制 粘贴 ctrl a 全选 ctrl s 保存 ctrl f 查找 ctrl z 撤销 ctrl x 剪切 win r 命令运行框 win d 隐藏 显示当前页面或者应用 win l 锁屏 alt Ta
  • json数组如何转换成string类型(超级好用)

    先上代码 下面解释 这个jar包地址之后更新的时候再给出来的 包的地址 JSONObject job ace text a 此时job里面的数据格式为 logid 2075 words result words acb words and
  • Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0

    项目 taro3 vue3 描述 运行时警告 Deprecation Warning Using for division outside of calc is deprecated and will be removed in Dart
  • LeetCode 102. 二叉树的层序遍历BFS

    LeetCode 102 二叉树的层序遍历BFS 给你二叉树的根节点 root 返回其节点值的 层序遍历 即逐层地 从左到右访问所有节点 示例 1 输入 root 3 9 20 null null 15 7 输出 3 9 20 15 7 示
  • 机器学习:正则化

    正则化 引入正则化的目的是为了解决过拟合问题 左边的图中蓝色的线是目标函数 随机产生五个带噪声的点 我们理想的拟合曲线为红色的线 虽然有些许误差 但是整体拟合情况和目标函数接近 但是 事先不知道需要用二次曲线来拟合这些点 如果使用了更高次方
  • Vue2/Vue3 响应式原理

    Vue 2 x 版本与 Vue 3 x 版本的响应式实现有所不同 Vue 2 x 响应式基于 ES5 的 Object defineProperty 实现 Vue 3 x 响应式基于 ES6 的 Proxy 实现 Vue 2 响应式原理 V
  • Halcon与WPF联合编程

    环境 VS2017 halcon12 1 新建WPF应用程序完成后 解决方案资源管理器 引用处右键 添加引用如下两个dll 只引入第一个也可以 2 工具箱 空白处右键 选择项 只添加halcondotnet dll 文件位置同上 这样hal
  • 【TVM帮助文档学习】开始使用TVMC Python: TVM的高级API

    本文翻译自Getting Starting using TVMC Python a high level API for TVM tvm 0 9 dev0 documentation 首先我们需要准备好示例使用resnet模型 如果你还没有
  • [技术分享]Android平台实时音视频录像模块设计之道

    实现背景 录像有什么难的 无非就是数据过来 编码保存mp4而已 这可能是好多开发者在做录像模块的时候的思考输出 是的 确实不难 但是做好 或者和其他模块有非常好的逻辑配合 确实不容易 好多开发者希望聊聊录像模块 实际上录像这块 需求层面的东
  • 浏览器缓存机制及其分类

    聚沙成塔 每天进步一点点 专栏简介 强缓存 Cache Control 和 Expires 协商缓存 ETag 和 Last Modified 写在最后 专栏简介 前端入门之旅 探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦
  • 解决ros安装 使用roscore命令测试问题

    本人安装教程完成ROS的安装后 在进行测试如图1命令 出现 解决办法输入完命令1后要输入命令2才行 即可测试成功 测试成功的界面如下
  • caxa线切割怎样画链轮,收藏:Autocad实战教程-线切割画链轮

    Autocad实战教程 线切割画链轮 今天小编为各位朋友准备的内容是Autocad实战教程 线切割画链轮 希望能对各位朋友有所帮助 用AutoCAD绘制链轮首先要知道一些参数 d1为链条滚子直径 套铜直径 p为节距 链条两孔中心的距离也是链
  • c/c++开发时的VsCode插件

    Name Align Spaces Id OldStarchy align spaces Description Align operators without modifying the code 在不修改代码的情况下对齐操作符 Vers
  • 华为杯数学建模(准备)<2018 - 2022>

    前言 这里简单总结一些资料 为后期个人参赛做准备 其中的优秀案例皆以博客 链接的形式总结归纳 详细见对应原作者博客 基础知识 一些需要提前掌握的算法 1 时间序列算法 拟合插值算法 基础的图论算法 2 多元线性回归 3 整数规划 线性规划
  • 8. 让java性能提升的JIT深度解剖

    JVM性能调优 1 C1 C2与Graal编译器 1 1 C1编译器 1 2 C2编译器 1 3 分层编译 2 热点代码 3 热点探测 4 方法调用计数器 5 回边计数器 6 编译优化技术 6 1 方法内联 7 锁消除 8 栈上分配 9 逃