JVM学习~

https://www.bilibili.com/video/av45092487?from=search&seid=1467414464079637031

https://www.bilibili.com/video/BV1yE411Z7AP?t=415&p=149 非常好

JVM Server与Client运行模式

  • 可以通过-server或-client设置jvm的运行参数。它们的区别是Server VM的初始堆空间会大一些,默认使用的是并行垃圾回收器,启动慢运行快。
  • Client VM相对来讲会保守一些,初始堆空间会小一些,使用串行的垃圾回收器,它的目标是为了让JVM的启动速度更快,但运行速度会比Serverm模式慢些。JVM在启动的时候会根据硬件和操作系统自动选择使用Server还是Client类型的JVM。
  • 32位操作系统

如果是Windows系统,不论硬件配置如何,都默认使用Client类型的JVM。如果是其他操作系统上,机器配置有2GB以上的内存同时有2个以上CPU的话默认使用server模式,否则使用client模式。

  • 64位操作系统

只有server类型,不支持client类型

[root@node01 test]# java ‐client ‐showversion TestJVM
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)
Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode)
itcast
[root@node01 test]# java ‐server ‐showversion TestJVM
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141‐b15)
Java HotSpot(TM) 64‐Bit Server VM (build 25.141‐b15, mixed mode)
itcast
#由于机器是64位系统,所以不支持client模式

JVM常用运行参数:

初级参数:

示例

 -Xms512m -Xmx512m -Xss256k -XX:MaxDirectMemorySize=256m -XX:+UseParallelOldGC -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails -verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:gc.log

高级参数:

收集器设置

-XX:+UseSerialGC:设置串行收集器

-XX:+UseParallelGC:设置并行收集器

-XX:+UseParallelOldGC:老年代使用并行回收收集器

-XX:+UseParNewGC:在新生代使用并行收集器

-XX:+UseParalledlOldGC:设置并行老年代收集器

-XX:+UseConcMarkSweepGC:设置CMS并发收集器

-XX:+UseG1GC:设置G1收集器

-XX:ParallelGCThreads:设置用于垃圾回收的线程数

并行收集器设置

-XX:ParallelGCThreads:设置并行收集器收集时使用的CPU数。并行收集线程数。

-XX:MaxGCPauseMillis:设置并行收集最大暂停时间

-XX:GCTimeRatio:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

CMS收集器设置

-XX:+UseConcMarkSweepGC:设置CMS并发收集器

-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。

-XX:ParallelGCThreads:设置并发收集器新生代收集方式为并行收集时,使用的CPU数。并行收集线程数。

-XX:CMSFullGCsBeforeCompaction:设定进行多少次CMS垃圾回收后,进行一次内存压缩

-XX:+CMSClassUnloadingEnabled:允许对类元数据进行回收

-XX:UseCMSInitiatingOccupancyOnly:表示只在到达阀值的时候,才进行CMS回收

-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况

-XX:ParallelCMSThreads:设定CMS的线程数量

-XX:CMSInitiatingOccupancyFraction:设置CMS收集器在老年代空间被使用多少后触发

-XX:+UseCMSCompactAtFullCollection:设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片的整理

G1收集器设置

-XX:+UseG1GC:使用G1收集器

-XX:ParallelGCThreads:指定GC工作的线程数量

-XX:G1HeapRegionSize:指定分区大小(1MB~32MB,且必须是2的幂),默认将整堆划分为2048个分区

-XX:GCTimeRatio:吞吐量大小,0-100的整数(默认9),值为n则系统将花费不超过1/(1+n)的时间用于垃圾收集

-XX:MaxGCPauseMillis:目标暂停时间(默认200ms)

-XX:G1NewSizePercent:新生代内存初始空间(默认整堆5%)

-XX:G1MaxNewSizePercent:新生代内存最大空间

-XX:TargetSurvivorRatio:Survivor填充容量(默认50%)

-XX:MaxTenuringThreshold:最大任期阈值(默认15)

-XX:InitiatingHeapOccupancyPercen:老年代占用空间超过整堆比IHOP阈值(默认45%),超过则执行混合收集

-XX:G1HeapWastePercent:堆废物百分比(默认5%)

-XX:G1MixedGCCountTarget:参数混合周期的最大总次数(默认8)

JVM内存模型

程序计数器线程私有

就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间

作用,是记住下一条jvm指令的执行地址
特点

  • 是线程私有的
  • 不会存在内存溢出

作用:

执行顺序:jvm指令->解释器->机器码->CPU执行

虚拟机栈

  • 也叫Java: Java线程执行方法的内存模型,一个线程对应一个栈,每个方法在执行的同时都会创建一个栈帧(用于存储局部变量表,操作数栈,动态链接,方法出口等信息)不存在垃圾回收问题,只要线程一结束该栈就释放,生命周期和线程一致
• JVM 对该区域规范了两种异常:

1) 线程请求的栈深度大于虚拟机栈所允许的深度,将抛出StackOverFlowError异常 (递归)

2) 若虚拟机栈可动态扩展,当无法申请到足够内存空间时将抛出OutOfMemoryError,通过jvm参数–Xss指定栈空间,空间大小决定函数调用的深度  (栈帧过大导致栈内存溢出  很少见) 64位操作系统栈空间大小一般1M

问题辨析

  1. 垃圾回收是否涉及栈内存? 不需要,栈帧内存在每次方法调用结束后会被函数栈自动回收

  2. 栈内存分配越大越好吗?不是,栈内存变大只是增大递归次数,但是却减少了线程数。例如,一个栈内存大小时为1M,物理内存有500M,就是500个线程,若占内存大小变为2M,线程数变为250个

  3. 方法内的局部变量是否线程安全?

    • 如果方法内局部变量没有逃离方法的作用访问,它是线程安全的

    • 如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

本地方法栈

登记native方法,在Execution Engine执行时加载本地方法库,比如被native修饰的函数,底层调用c/c++函数类库。

比如object对象的:

public final native Class<?> getClass();

protected native Object clone() throws CloneNotSupportedException;

public final native void notify();

public final native void notifyAll();

堆内存模型

  • 通过 new 关键字,创建对象都会使用堆内存
  • 它是线程共享的,堆中对象都需要考虑线程安全的问题
  • 有垃圾回收机制

jvm的内存模型在1.7和1.8有较大的区别,虽然本套课程是以1.8为例进行讲解,但是我们也是需要对1.7的内存模型有所了解,所以接下里,我们将先学习1.7再学习1.8的内存模型

jdk1.7的内存模型

  • Young 年轻区(代)

Young区被划分为三部分,Eden区和两个大小严格相同的Survivor区,Survivor幸存区有两个:From区(Survivor 0 space)和To区(Survivor 1 space)

在Survivor区间中,某一时刻只有其中一个是被使用的,另外一个留做垃圾收集时复制对象用,在Eden区间变满的时候, ,程序又需要创建对象,JVM的垃圾回收器将对Eden区进行垃圾回收(Minor GC),将Eden区中的不再被其他对象所引用的对象进行销毁。然后将Eden区中的剩余对象移动到Survivor From区,若幸存 From区也满了,再对该区进行垃圾回收,然后将存活的对象移动到Survivor  To区,并将Survivor From清空;此时From和To区交换角色,Eden区再有存活对象时,需要移动到Survivor From了,此时From和To区交换角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前
的“To”,交替上述过程,根据JVM的策略,Survivor区在经过几次垃圾收集后(默认是15次,可以通过-XX:MaxTenuringThreshold参数设定),任然存活于Survivor的对象将被移动到Tenured区间。

  • Tenured 年老区

Tenured区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在Young复制转移一定的次数以后,对象就会被转移到Tenured区,一般如果系统中用了application级别的缓存,缓存中的对象往往会被转移到这一区间。若老年区也满了,那么这个时候将产生MajorGCFullGC,进行老年区的内存清理。若老年区执行了Full GC之后发现依然无法进行对象的保存,就会产生OOM异常“OutOfMemoryError”

  • Perm 永久区

Perm代主要保存class,method,filed对象,这部份的空间一般不会溢出,除非一次性加载了很多的类,不过在涉及到热部署的应用服务器的时候,有时候会遇到java.lang.OutOfMemoryError : PermGen space 的错误,造成这个错误的很大原因
就有可能是每次都重新部署,但是重新部署后,类的class没有被卸载掉,这样就造成了大量的class对象保存在了perm中,这种情况下,一般重新启动应用服务器可以解决问题。

  • Virtual区:

最大内存和初始内存的差值,就是Virtual区

 jdk1.8的堆内存模型

由上图可以看出,jdk1.8的内存模型是由2部分组成,年轻代 + 年老代。
年轻代:Eden + 2*Survivor
年老代:OldGen
在jdk1.8中变化最大的Perm区,用Metaspace(元数据空间)进行了替换。
需要特别说明的是:Metaspace所占用的内存空间不是在虚拟机内部,而是在本地内存
空间中,这也是与1.7的永久代最大的区别所在

从堆内存分配大小维度看,年轻代和老年代默认分别占用堆内存总量的1/3和2/3;eden区默认占用年轻代的8/10,Survivor0和Survivor1各占年轻代1/10

Metaspace详细解析:

元数据区元数据区取代了永久代(jdk1.8以前),本质和永久代类似,都是对JVM规范中方法区的实现,区别在于元数据区并不在虚拟机中,而是使用本地物理内存,永久代在虚拟机中,永久代逻辑结构上属于堆,但是物理上不属于堆,堆大小=新生代+老年代。元数据区也有可能发生OutOfMemory异常。

Jdk1.6及之前: 有永久代, 常量池在方法区

Jdk1.7:       有永久代,但已经逐步“去永久代”,常量池在堆

Jdk1.8及之后: 无永久代,常量池在元空间

元数据区的动态扩展,默认–XX:MetaspaceSize值为21MB的高水位线。一旦触及则Full GC将被触发并卸载没有用的类(类对应的类加载器不再存活),然后高水位线将会重置。新的高水位线的值取决于GC后释放的元空间。如果释放的空间少,这个高水位线则上升。如果释放空间过多,则高水位线下降。

为什么jdk1.8用元数据区取代了永久代?

  • 官方解释:移除永久代是为融合HotSpot JVM与 JRockit VM而做出的努力,因为JRockit没有永久代,不需要配置永久代
  • 现实使用中,由于永久代内存经常不够用或发生内存泄露,爆出异常java.lang.OutOfMemoryError: PermGen。基于此,将永久区废弃,而改用元空间,改为了使用本地内存空间

方法区(线程共享)

类的所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。简单说,所有定义的方法的信息都保存在该区域,静态变量+常量+类信息(构造方法/接口定义)+运行时常量池都存在方法区中,虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来

JVM规范-方法区定义

Java虚拟机有一个方法区域,在所有Java虚拟机线程之间共享。方法区域类似于常规语言编译代码的存储区域,或者类似于操作系统进程中的“文本”段。它存储每类结构,如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括在类和实例初始化以及接口初始化中使用的特殊方法(§2.9)。

方法区域是在虚拟机启动时创建的。尽管方法区域在逻辑上是堆的一部分,但是简单的实现可以选择不垃圾收集或压缩它。此规范不强制指定用于管理已编译代码的方法区域或策略的位置。方法区域可以是固定大小的,或者可以根据计算的需要进行扩展,并且如果不需要更大的方法区域,则可以收缩。方法区域的内存不需要是连续的。

Java虚拟机实现可以向程序员或用户提供对方法区域的初始大小的控制,并且,在大小不同的方法区域的情况下,还可以提供对最大和最小方法区域大小的控制。

以下例外情况与方法区域相关:

如果方法区域中的内存无法满足分配请求,Java虚拟机将抛出OutOfMemoryError。

方法区内存溢出:

1.8 以前会导致永久代内存溢出

* 演示永久代内存溢出  java.lang.OutOfMemoryError: PermGen space
* -XX:MaxPermSize=8m

1.8 之后会导致元空间内存溢出

元空间内存溢出 java.lang.OutOfMemoryError: Metaspace
package cn.itcast.jvm.t1.metaspace;import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Opcodes;/*** 演示元空间内存溢出 java.lang.OutOfMemoryError: Metaspace* -XX:MaxMetaspaceSize=8m*/
public class Demo1_8 extends ClassLoader { // 可以用来加载类的二进制字节码public static void main(String[] args) {int j = 0;try {Demo1_8 test = new Demo1_8();for (int i = 0; i < 10000; i++, j++) {// ClassWriter 作用是生成类的二进制字节码ClassWriter cw = new ClassWriter(0);// 版本号, public, 类名, 包名, 父类, 接口cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null);// 返回 byte[]byte[] code = cw.toByteArray();// 执行了类的加载test.defineClass("Class" + i, code, 0, code.length); // Class 对象}} finally {System.out.println(j);}}
}

5411
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
    at cn.itcast.jvm.t1.metaspace.Demo1_8.main(Demo1_8.java:23)

运行时常量池

常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息

实例,一段简单的HelloWrold程序反编译后的结果

// 二进制字节码(类基本信息,常量池,类方法定义,包含了虚拟机指令)
public class HelloWorld {public static void main(String[] args) {System.out.println("hello world");}
}
F:\视频-解密JVM\资料 解密JVM\代码\jvm\jvm\src\cn\itcast\jvm\t5>javap -v HelloWorld.class
Classfile /F:/视频-解密JVM/资料 解密JVM/代码/jvm/jvm/src/cn/itcast/jvm/t5/HelloWorld.classLast modified 2020-4-26; size 442 bytesMD5 checksum 103606e24ec918e862312533fda15bbcCompiled from "HelloWorld.java"
public class cn.itcast.jvm.t5.HelloWorldminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER===================类的基本信息========================
Constant pool:#1 = Methodref          #6.#15         // java/lang/Object."<init>":()V#2 = Fieldref           #16.#17        // java/lang/System.out:Ljava/io/PrintStream;#3 = String             #18            // hello world#4 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V#5 = Class              #21            // cn/itcast/jvm/t5/HelloWorld#6 = Class              #22            // java/lang/Object#7 = Utf8               <init>#8 = Utf8               ()V#9 = Utf8               Code#10 = Utf8               LineNumberTable#11 = Utf8               main#12 = Utf8               ([Ljava/lang/String;)V#13 = Utf8               SourceFile#14 = Utf8               HelloWorld.java#15 = NameAndType        #7:#8          // "<init>":()V#16 = Class              #23            // java/lang/System#17 = NameAndType        #24:#25        // out:Ljava/io/PrintStream;#18 = Utf8               hello world#19 = Class              #26            // java/io/PrintStream#20 = NameAndType        #27:#28        // println:(Ljava/lang/String;)V#21 = Utf8               cn/itcast/jvm/t5/HelloWorld#22 = Utf8               java/lang/Object#23 = Utf8               java/lang/System#24 = Utf8               out#25 = Utf8               Ljava/io/PrintStream;#26 = Utf8               java/io/PrintStream#27 = Utf8               println#28 = Utf8               (Ljava/lang/String;)V//类方法的定义
{public cn.itcast.jvm.t5.HelloWorld();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 4: 0public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=1, args_size=1//jvm的指令0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc           #3                  // String hello world5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: returnLineNumberTable:line 6: 0line 7: 8
}
SourceFile: "HelloWorld.java"

运行时常量池,常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址

直接内存

定义

Direct Memory
常见于 NIO 操作时,用于数据缓冲区
分配回收成本较高,但读写性能高
不受 JVM 内存回收管理

使用io读写时的原理:

使用NIO读写时原理:

package cn.itcast.jvm.t1.direct;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;/*** 演示 ByteBuffer 作用*/
public class Demo1_9 {static final String FROM = "E:\\编程资料\\第三方教学视频\\youtube\\Getting Started with Spring Boot-sbPSjI4tt10.mp4";static final String TO = "E:\\a.mp4";static final int _1Mb = 1024 * 1024;public static void main(String[] args) {io(); // io 用时:1535.586957 1766.963399 1359.240226directBuffer(); // directBuffer 用时:479.295165 702.291454 562.56592}private static void directBuffer() {long start = System.nanoTime();try (FileChannel from = new FileInputStream(FROM).getChannel();FileChannel to = new FileOutputStream(TO).getChannel();) {ByteBuffer bb = ByteBuffer.allocateDirect(_1Mb);while (true) {int len = from.read(bb);if (len == -1) {break;}bb.flip();to.write(bb);bb.clear();}} catch (IOException e) {e.printStackTrace();}long end = System.nanoTime();System.out.println("directBuffer 用时:" + (end - start) / 1000_000.0);}private static void io() {long start = System.nanoTime();try (FileInputStream from = new FileInputStream(FROM);FileOutputStream to = new FileOutputStream(TO);) {byte[] buf = new byte[_1Mb];while (true) {int len = from.read(buf);if (len == -1) {break;}to.write(buf, 0, len);}} catch (IOException e) {e.printStackTrace();}long end = System.nanoTime();System.out.println("io 用时:" + (end - start) / 1000_000.0);}
}

分配和回收原理

  • 使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法
  • ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调用 freeMemory 来释放直接内存
package cn.itcast.jvm.t1.direct;import java.io.IOException;
import java.nio.ByteBuffer;/*** 禁用显式回收对直接内存的影响*/
public class Demo1_26 {static int _1Gb = 1024 * 1024 * 1024;/** -XX:+DisableExplicitGC 显式的*/public static void main(String[] args) throws IOException {ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_1Gb);System.out.println("分配完毕...");System.in.read();System.out.println("开始释放...");byteBuffer = null;System.gc(); // 显式的垃圾回收,Full GCSystem.in.read();}
}

1-JVM 运行参数和内存模型相关推荐

  1. JVM运行参数_JVM内存模型_常用内存分析工具

    JVM运行参数 常见标准参数 -showversion: 显示当前JVM版本等信息 -D设置系统属性参数: /*** 测试* @author regotto*/ public class JvmTes ...

  2. JVM调优:运行参数,内存模型,mat、jps、jstat、jmap、jstack、jvisualvm工具的使用

    JVM调优 - 工具篇 作者:张学亮 讲解内容 了解下我们为什么要学习JVM优化 掌握jvm的运行参数以及参数的设置 掌握jvm的内存模型(堆内存) 掌握jamp命令的使用以及通过MAT工具进行分析 ...

  3. JVM运行时的内存结构

    我们都知道,JVM的垃圾收集机制能够帮开发者自动管理内存,了解JVM运行时的内存结构是理解垃圾收集机制的前提.本文主要简单介绍JVM运行时的内存结构. [JVM运行时内存中不同的数据区域] 一.PC寄 ...

  4. 在linux中怎么查看jvm堆内存大小,如何查看JVM运行的堆内存情况

    <不可不知的7个JDK命令>介绍了些jdk自带的问题排查工具,机器出现CPU飙升的情况,此时就可以借助工具,排查应用端是否存在一些潜在问题. jmap指令可以查看JVM运行的堆内存情况, ...

  5. JVM垃圾回收系列--内存模型/垃圾回收流程

    原文网址:JVM垃圾回收系列--内存模型/垃圾回收流程_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Java各个代的关系(内存模型)及垃圾收集流程. 内存模型 JDK8的内存模型 在Java中所有 ...

  6. 利用jmap和MAT等工具查看JVM运行时堆内存

    2019独角兽企业重金招聘Python工程师标准>>> jmap JDK自带了一些工具可以帮助我们查看JVM运行的堆内存情况,常用的是jmap命令 如果想学习Java工程化.高性能及 ...

  7. idea设置JVM运行参数

    对JVM运行参数进行修改是JVM性能调优的重要手段,下面介绍在应用程序开发过程中JVM参数设置的几种方式. 方式一 java程序运行时指定 -Dproperty=value 该参数通常用于设置系统级全 ...

  8. java jmap mat_利用jmap和MAT等工具查看JVM运行时堆内存

    jmap JDK自带了一些工具可以帮助我们查看JVM运行的堆内存情况,常用的是jmap命令 如果想学习Java工程化.高性能及分布式.深入浅出.微服务.Spring,MyBatis,Netty源码分析 ...

  9. java中数组的内存模型_Java如何在内存有限的情况下实现一个超大数组?jvm性能调优+内存模型+虚拟机原理能解决什么样问题...

    在上一篇文章中,小编为您详细介绍了关于<变频器调速问题?三星R458更换CPU>相关知识.本篇中小编将再为您讲解标题Java如何在内存有限的情况下实现一个超大数组?jvm性能调优+内存模型 ...

最新文章

  1. k8s 下线node正确处理姿势
  2. Http压测工具wrk使用指南【转】
  3. 谈几个初学者混淆不清的问题
  4. Linux进程描述符task_struct结构体详解--Linux进程的管理与调度(一)
  5. linux经典书籍--Linux系统编程
  6. mysql截取字符串中的部分内容_Mysql字符串截取及获取指定字符串中的数据
  7. [JavaWeb-Servlet]IDEA与Tomcat的相关配置
  8. (C++版)链表(二)——实现单项循环链表创建、插入、删除等操作
  9. swagger2maven依赖_Maven + SpringMVC项目集成Swagger
  10. 边工作边刷题:70天一遍leetcode: day 6
  11. Unity 编辑器扩展教程
  12. python 阮一峰_ES6 Iterator笔记(摘抄至阮一峰的ECMAScript 6入门)
  13. java 计算机概述看这一篇文章就够了
  14. samba配置共享打印机
  15. NodeJs string与base64互转
  16. windows系统搭建portal服务器,Windows下安装部署OpenPortal1.1
  17. numpy、pandas下载速度慢问题
  18. 这辈子会遇见谁,早已命中注定
  19. IDEA 2021.1 的 Win 和 Mac 快捷键大全!!
  20. python画spc控制图_SPC系列8:如何选择计数型数据的SPC控制图?

热门文章

  1. 民锋国际期货量化交易策略源代码大全
  2. NoSQL概述、NoSQL数据库的分类、主流产品及特点
  3. ffmpeg录制屏幕和截屏
  4. Ajax是什么?Ajax高级用法之Axios技术
  5. C语言字符串数组拼接
  6. mysql存储过程基本语法_Oracle存储过程基本语法
  7. Python输入/判断/循环练习题
  8. 教程:手机数据恢复 安卓设备内置存储器创建镜像到电脑数据恢复
  9. JIT 即时编译 (史上最全)
  10. 《SRE Google运维解密》读书笔记