JVM调优实战及常量池详解

news2024/11/26 5:39:48

阿里巴巴Arthas详解

Arthas 是 Alibaba 在 2018 年 9 月开源的 Java 诊断工具。支持 JDK6+, 采用命令行交互模式,可以方便的定位和诊断线上程序运行问题。Arthas 官方文档十分详细,详见:https://alibaba.github.io/arthas

Arthas使用场景

得益于 Arthas 强大且丰富的功能,让 Arthas 能做的事情超乎想象。下面仅仅列举几项常见的使用情况,更多的使用场景可以在熟悉了 Arthas 之后自行探索。

  1. 是否有一个全局视角来查看系统的运行状况?
  2. 为什么 CPU 又升高了,到底是哪里占用了 CPU ?
  3. 运行的多线程有死锁吗?有阻塞吗?
  4. 程序运行耗时很长,是哪里耗时比较长呢?如何监测呢?
  5. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  6. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  7. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  8. 有什么办法可以监控到 JVM 的实时运行状态?

Arthas使用

# github下载arthas 
wget https://alibaba.github.io/arthas/arthas-boot.jar 
# 或者 Gitee 下载 
wget https://arthas.gitee.io/arthas-boot.jar  

用java -jar运行即可,可以识别机器上所有Java进程(我们这里之前已经运行了一个Arthas测试程序

0

选择进程序号1,进入进程信息操作

0

输入dashboard可以查看整个进程的运行情况,线程、内存、GC、运行环境信息:

0

输入thread可以查看线程详细情况

0

输入 thread加上线程ID 可以查看线程堆栈

0

输入 thread -b 可以查看线程死锁

0

输入 jad加类的全名 可以反编译,这样可以方便我们查看线上代码是否是正确的版本

0

使用 ognl 命令可以查看变量值

0

设置变量值

0

更多命令使用可以用help命令查看,或查看文档:https://alibaba.github.io/arthas/commands.html#arthas

GC日志详解

对于java应用我们可以通过一些配置把程序运行过程中的gc日志全部打印出来,然后分析gc日志得到关键性指标,分析GC原因,调优JVM参数。

打印GC日志方法,在JVM参数里增加参数,%t 代表时间

-Xloggc:./gc-%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps  -XX:+PrintGCTimeStamps -XX:+PrintGCCause   -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M

Tomcat则直接加在JAVA_OPTS变量里。

如何分析GC日志

运行程序加上对应gc日志

java -jar -Xloggc:./gc-%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps  -XX:+PrintGCTimeStamps -XX:+PrintGCCause   -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M microservice-eureka-server.jar

下图中是我截取的JVM刚启动的一部分GC日志

0

我们可以看到图中第一行红框,是项目的配置参数。这里不仅配置了打印GC日志,还有相关的VM内存参数。

第二行红框中的是在这个GC时间点发生GC之后相关GC情况。

1、对于2.909: 这是从jvm启动开始计算到这次GC经过的时间,前面还有具体的发生时间日期。

2、Full GC(Metadata GC Threshold)指这是一次full gc,括号里是gc的原因, PSYoungGen是年轻代的GC,ParOldGen是老年代的GC,Metaspace是元空间的GC

3、 6160K->0K(141824K),这三个数字分别对应GC之前占用年轻代的大小,GC之后年轻代占用,以及整个年轻代的大小。

4、112K->6056K(95744K),这三个数字分别对应GC之前占用老年代的大小,GC之后老年代占用,以及整个老年代的大小。

5、6272K->6056K(237568K),这三个数字分别对应GC之前占用堆内存的大小,GC之后堆内存占用,以及整个堆内存的大小。

6、20516K->20516K(1069056K),这三个数字分别对应GC之前占用元空间内存的大小,GC之后元空间内存占用,以及整个元空间内存的大小。

7、0.0209707是该时间点GC总耗费时间。

从日志可以发现几次fullgc都是由于元空间不够导致的,所以我们可以将元空间调大点

java -jar -Xloggc:./gc-adjust-%t.log -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps   -XX:+PrintGCTimeStamps -XX:+PrintGCCause  -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M  microservice-eureka-server.jar 

调整完我们再看下gc日志发现已经没有因为元空间不够导致的full gc了

对于CMS和G1收集器的日志会有一点不一样,也可以试着打印下对应的gc日志分析下,可以发现gc日志里面的gc步骤跟我们之前讲过的步骤是类似的

public class HeapTest {      
	byte[] a = new byte[1024 * 100];  //100KB      
	public static void main(String[] args) throws InterruptedException {         
		ArrayList<HeapTest> heapTests = new ArrayList<>();         
		while (true) {             
			heapTests.add(new HeapTest());             
			Thread.sleep(10);         
		}     
	} 
}

CMS

-Xloggc:d:/gc-cms-%t.log -Xms50M -Xmx50M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps    -XX:+PrintGCTimeStamps -XX:+PrintGCCause  -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M   -XX:+UseParNewGC -XX:+UseConcMarkSweepGC   

G1

-Xloggc:d:/gc-g1-%t.log -Xms50M -Xmx50M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps    -XX:+PrintGCTimeStamps -XX:+PrintGCCause  -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UseG1GC     

上面的这些参数,能够帮我们查看分析GC的垃圾收集情况。但是如果GC日志很多很多,成千上万行。就算你一目十行,看完了,脑子也是一片空白。所以我们可以借助一些功能来帮助我们分析,这里推荐一个gceasy(https://gceasy.io),可以上传gc文件,然后他会利用可视化的界面来展现GC情况。具体下图所示

0

上图我们可以看到年轻代,老年代,以及永久代的内存分配,和最大使用情况。

0

上图我们可以看到堆内存在GC之前和之后的变化,以及其他信息。

这个工具还提供基于机器学习的JVM智能优化建议,当然现在这个功能需要付费

0

0

JVM参数汇总查看命令


java -XX:+PrintFlagsInitial 表示打印出所有参数选项的默认值

java -XX:+PrintFlagsFinal 表示打印出所有参数选项在运行程序时生效的值

Class常量池与运行时常量池


Class常量池可以理解为是Class文件中的资源仓库。 Class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table),用于存放编译期生成的各种字面量(Literal)和符号引用(Symbolic References)

一个class文件的16进制大体结构如下图:

0

对应的含义如下,细节可以查下oracle官方文档

0

当然我们一般不会去人工解析这种16进制的字节码文件,我们一般可以通过javap命令生成更可读的JVM字节码指令文件:

javap -v Math.class

0

红框标出的就是class常量池信息,常量池中主要存放两大类常量:字面量和符号引用

字面量

字面量就是指由字母、数字等构成的字符串或者数值常量

字面量只可以右值出现,所谓右值是指等号右边的值,如:int a=1 这里的a为左值,1为右值。在这个例子中1就是字面量。

int a = 1; 
int b = 2; 
int c = "abcdefg"; 
int d = "abcdefg";   

符号引用

符号引用是编译原理中的概念,是相对于直接引用来说的。主要包括了以下三类常量:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

上面的a,b就是字段名称,就是一种符号引用,还有Math类常量池里的 Lcom/tuling/jvm/Math 是类的全限定名,main和compute是方法名称,()是一种UTF8格式的描述符,这些都是符号引用。

这些常量池现在是静态信息,只有到运行时被加载到内存后,这些符号才有对应的内存地址信息,这些常量池一旦被装入内存就变成运行时常量池,对应的符号引用在程序加载或运行时会被转变为被加载到内存区域的代码的直接引用,也就是我们说的动态链接了。例如,compute()这个符号引用在运行时就会被转变为compute()方法具体代码在内存中的地址,主要通过对象头里的类型指针去转换直接引用。

字符串常量池

字符串常量池的设计思想

  1. 字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能
  2. JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化
  • 为字符串开辟一个字符串常量池,类似于缓存区
  • 创建字符串常量时,首先查询字符串常量池是否存在该字符串
  • 存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中

三种字符串操作(Jdk1.7 及以上版本)

  • 直接赋值字符串
String s = "zhuge";  // s指向常量池中的引用    

这种方式创建的字符串对象,只会在常量池中。

因为有"zhuge"这个字面量,创建对象s的时候,JVM会先去常量池中通过 equals(key) 方法,判断是否有相同的对象

如果有,则直接返回该对象在常量池中的引用;

如果没有,则会在常量池中创建一个新对象,再返回引用。

  • new String();
String s1 = new String("zhuge");  // s1指向内存中的对象引用 

这种方式会保证字符串常量池和堆中都有这个对象,没有就创建,最后返回堆内存中的对象引用。

步骤大致如下:

因为有"zhuge"这个字面量,所以会先检查字符串常量池中是否存在字符串"zhuge"不存在,先在字符串常量池里创建一个字符串对象;再去内存中创建一个字符串对象"zhuge";

存在的话,就直接去堆内存中创建一个字符串对象"zhuge";

最后,将内存中的引用返回。

  • intern方法
String s1 = new String("zhuge");    
String s2 = s1.intern();  
System.out.println(s1 == s2);  //false  

String中的intern方法是一个 native 的方法,当调用 intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(oject)方法确定),则返回池中的字符串。否则,将intern返回的引用指向当前字符串 s1(jdk1.6版本需要将 s1 复制到字符串常量池里)。

字符串常量池位置

Jdk1.6及之前: 有永久代, 运行时常量池在永久代,运行时常量池包含字符串常量池

Jdk1.7:有永久代,但已经逐步“去永久代”,字符串常量池从永久代里的运行时常量池分离到堆里

Jdk1.8及之后: 无永久代,运行时常量池在元空间,字符串常量池里依然在堆里

用一个程序证明下字符串常量池在哪里:

/**  
* jdk6:-Xms6M -Xmx6M -XX:PermSize=6M -XX:MaxPermSize=6M    
* jdk8:-Xms6M -Xmx6M -XX:MetaspaceSize=6M -XX:MaxMetaspaceSize=6M  
*/ 
public class RuntimeConstantPoolOOM{     
	public static void main(String[] args) {         
		ArrayList<String> list = new ArrayList<String>();         
		for (int i = 0; i < 10000000; i++) {             
			String str = String.valueOf(i).intern();             
			list.add(str);         
		}     
	} 
}  
运行结果: 
jdk7及以上:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
jdk6:Exception in thread "main" java.lang.OutOfMemoryError: PermGen space  ​                  

字符串常量池设计原理

字符串常量池底层是hotspot的C++实现的,底层类似一个 HashTable, 保存的本质上是字符串对象的引用。

看一道比较常见的面试题,下面的代码创建了多少个 String 对象?

String s1 = new String("he") + new String("llo"); 
String s2 = s1.intern();   
System.out.println(s1 == s2); 
// 在 JDK 1.6 下输出是 false,创建了 6 个对象 
// 在 JDK 1.7 及以上的版本输出是 true,创建了 5 个对象 
// 当然我们这里没有考虑GC,但这些对象确实存在或存在过      

为什么输出会有这些变化呢?主要还是字符串池从永久代中脱离、移入堆区的原因, intern() 方法也相应发生了变化:

1、在 JDK 1.6 中,调用 intern() 首先会在字符串池中寻找 equal() 相等的字符串,假如字符串存在就返回该字符串在字符串池中的引用;假如字符串不存在,虚拟机会重新在永久代上创建一个实例,将 StringTable 的一个表项指向这个新创建的实例。

0

2、在 JDK 1.7 (及以上版本)中,由于字符串池不在永久代了,intern() 做了一些修改,更方便地利用堆中的对象。字符串存在时和 JDK 1.6一样,但是字符串不存在时不再需要重新创建实例,可以直接指向堆上的实例。

0

由上面两个图,也不难理解为什么 JDK 1.6 字符串池溢出会抛出 OutOfMemoryError: PermGen space ,而在 JDK 1.7 及以上版本抛出 OutOfMemoryError: Java heap space 。

String常量池问题的几个例子

示例1:

String s0="zhuge"; 
String s1="zhuge"; 
String s2="zhu" + "ge"; 
System.out.println( s0==s1 ); //true 
System.out.println( s0==s2 ); //true  

分析:因为例子中的 s0和s1中的”zhuge”都是字符串常量,它们在编译期就被确定了,所以s0=s1为true;而”zhu”和”ge”也都是字符串常量,当一个字 符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被优化为一个字符串常量"zhuge",所以s2也是常量池中” zhuge”的一个引用。所以我们得出s0=s1=s2;

示例2:

String s0="zhuge"; 
String s1=new String("zhuge");
String s2="zhu" + new String("ge"); 
System.out.println( s0==s1 );  // false 
System.out.println( s0==s2 );  // false 
System.out.println( s1==s2 );  // false   

分析:用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。

s0还是常量池 中"zhuge”的引用,s1因为无法在编译期确定,所以是运行时创建的新对象”zhuge”的引用,s2因为有后半部分 new String(”ge”)所以也无法在编译期确定,所以也是一个新创建对象”zhuge”的引用;明白了这些也就知道为何得出此结果了。

示例3:

String a = "a1";   
String b = "a" + 1;   
System.out.println(a == b); // true       
String a = "atrue";   
String b = "a" + "true";   
System.out.println(a == b); // true       
String a = "a3.4";   
String b = "a" + 3.4;   
System.out.println(a == b); // true  

分析:JVM对于字符串常量的"+“号连接,将在程序编译期,JVM就将常量字符串的”+“连接优化为连接后的值,拿"a” + 1来说,经编译器优化后在class中就已经是a1。在编译期其字符串常量的值就确定下来,故上面程序最终的结果都为true。

示例4:

String a = "ab"; 
String bb = "b"; 
String b = "a" + bb;  
System.out.println(a == b); // false   

分析:JVM对于字符串引用,由于在字符串的"+“连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a” + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b。所以上面程序的结果也就为false。

示例5:

String a = "ab"; 
final String bb = "b"; 
String b = "a" + bb;  
System.out.println(a == b); // true    

分析:和示例4中唯一不同的是bb字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的"a" + bb和"a" + "b"效果是一样的。故上面程序的结果为true。

示例6:

String a = "ab"; 
final String bb = getBB(); 
String b = "a" + bb;  
System.out.println(a == b); // false  
private static String getBB()  {       
	return "b";   
}  

分析:JVM对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为b,故上面 程序的结果为false。

关于String是不可变的

​ 通过上面例子可以得出得知:

String  s  =  "a" + "b" + "c";  //就等价于String s = "abc"; 
String  a  =  "a"; 
String  b  =  "b"; 
String  c  =  "c"; 
String  s1  =   a  +  b  +  c;   

s1 这个就不一样了,可以通过观察其JVM指令码发现s1的"+"操作会变成如下操作:

StringBuilder temp = new StringBuilder(); 
temp.append(a).append(b).append(c); 
String s = temp.toString();   

最后再看一个例子

//字符串常量池:"计算机"和"技术"堆内存:str1引用的对象"计算机技术"   
//堆内存中还有个StringBuilder的对象,但是会被gc回收,StringBuilder的toString方法会new String(),这个String才是真正返回的对象引用 
String str2 = new StringBuilder("计算机").append("技术").toString();   //没有出现"计算机技术"字面量,所以不会在常量池里生成"计算机技术"对象 
System.out.println(str2 == str2.intern());  //true 
//"计算机技术" 在池中没有,但是在heap中存在,则intern时,会直接返回该heap中的引用  
//字符串常量池:"ja"和"va"堆内存:str1引用的对象"java"   
//堆内存中还有个StringBuilder的对象,但是会被gc回收,StringBuilder的toString方法会new String(),这个String才是真正返回的对象引用 
String str1 = new StringBuilder("ja").append("va").toString();    //没有出现"java"字面量,所以不会在常量池里生成"java"对象 
System.out.println(str1 == str1.intern());  //false 
//java是关键字,在JVM初始化的相关类里肯定早就放进字符串常量池了  
String s1=new String("test");   
System.out.println(s1==s1.intern());   //false 
//"test"作为字面量,放入了池中,而new时s1指向的是heap中新生成的string对象,s1.intern()指向的是"test"字面量之前在池中生成的字符串对象  
String s2=new StringBuilder("abc").toString(); 
System.out.println(s2==s2.intern());  //false 
//同上                

八种基本类型的包装类和对象池

java中基本类型的包装类的大部分都实现了常量池技术(严格来说应该叫**对象池,**在堆上),这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。因为一般这种比较小的数用到的概率相对较大。

public class Test {      
	public static void main(String[] args) {         
	//5种整形的包装类Byte,Short,Integer,Long,Character的对象,           
	//在值小于127时可以使用对象池           
	Integer i1 = 127;  //这种调用底层实际是执行的Integer.valueOf(127),里面用到了IntegerCache对象池         
	Integer i2 = 127;         
	System.out.println(i1 == i2);//输出true            
	//值大于127时,不会从对象池中取对象           
	Integer i3 = 128;         
	Integer i4 = 128;         
	System.out.println(i3 == i4);//输出false                    
	//用new关键词新生成对象不会使用对象池         
	Integer i5 = new Integer(127);           
	Integer i6 = new Integer(127);         
	System.out.println(i5 == i6);//输出false           
	//Boolean类也实现了对象池技术           
	Boolean bool1 = true;         
	Boolean bool2 = true;         
	System.out.println(bool1 == bool2);//输出true            
	//浮点类型的包装类没有实现对象池技术           
	Double d1 = 1.0;         
	Double d2 = 1.0;         
	System.out.println(d1 == d2);//输出false       
	} 
}  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1049399.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端uniapp防止页面整体滑动页面顶部以上,设置固定想要固定区域宽高

解决&#xff1a;设置固定想要固定区域宽高 目录 未改前图未改样式改后图改后样式 未改前图 未改样式 .main {display: flex;flex-direction: row;// justify-content: space-between;width: 100vw;// 防止全部移动到上面位置&#xff01;&#xff01;&#xff01;&#xff01…

排序:堆排序算法分析以及插入删除操作

堆排序可以看作顺序存储的完全二叉树。 堆排序属于选择排序的一种&#xff0c; 选择排序:每一趟在待排序元素中选取关键字最小(或最大&#xff09;的元素加入有序子序列。 1.堆的定义 若n个关键字序列 L [ 1... n ] L[ 1...n] L[1...n]满足下面某一条性质&#xff0c;则称为堆…

【Vue】监控路由与路由参数, 刷新当前页面数据的几种方法

目录 一、Vue监控路由 1、Vue中watch监控路由 2、Vue中watch监控路由的某一个参数 3、Vue中watch同时监控多个路由 二、刷新当前页面数据 1、location.reload 2、$router.go(0) 3、this.$router.resolve()与this.$router.resolve() a、this.$router.resolve() b、thi…

leetcode1610. 可见点的最大数目(java)

可见点的最大数目 题目描述滑动窗口 题目描述 难度 - 困难 leetcode1610. 可见点的最大数目 给你一个点数组 points 和一个表示角度的整数 angle &#xff0c;你的位置是 location &#xff0c;其中 location [posx, posy] 且 points[i] [xi, yi] 都表示 X-Y 平面上的整数坐标…

网络层五大核心知识点

引言 在前面几期文章中&#xff0c;无论是UDP还是TCP&#xff0c;其实我们都在介绍 TCP/IP 模型的“传输层”&#xff0c;我们知道&#xff0c;数据在传输层完成相应的封装后就会来到网络层进行下一步的数据转发&#xff0c;那么数据在网络层又接受了哪些神秘的力量&#xff1…

心法利器[102] | 大模型落地应用架构的一种模式

心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会&#xff0c;与大家一起成长。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。 2022年新一版的文章合集已经发布&#xff0c;累计已经60w字了&#xff0c;获取方式看这里&…

SAP替代物料的解决方案详解

说明&#xff1a; SAP中的替代有三种&#xff1a; A物料和B物料可以互相替代&#xff0c;但是由物料计划部门自由控制使用A还是使用B;在某个产品中&#xff0c;当物料A不够时&#xff0c;才用B&#xff1b;当物料A用完后&#xff0c;将永远不再用&#xff0c;而是用物料B取代A…

CYEZ 模拟赛 7

A 弹珠 妙妙题。 先每个组分一个小球。等价于 n − k n-k n−k 拆分为任意个 [ 1 , k ] [1,k] [1,k] 的数的方案数。 本质是根据面积的转换&#xff0c;直观解释&#xff1a; 完全背包即可。代码。 B C 总结

机器人制作开源方案 | 家庭清扫拾物机器人

作者&#xff1a;罗诚、李旭洋、胡旭、符粒楷 单位&#xff1a;南昌交通学院 人工智能学院 指导老师&#xff1a;揭吁菡 在家庭中我们有时无法到一些低矮阴暗的地方进行探索&#xff0c;比如茶几下或者床底下&#xff0c;特别是在部分家庭中&#xff0c;如果没有及时对这些阴…

设计加速!11个Adobe XD插件推荐!

你是否一直在寻找可以提升 Adobe XD 工作流程和体验的方法&#xff1f;如果是&#xff0c;一定要试试这些 Adobe XD 插件&#xff01;本文将介绍 11 款好用的 Adobe XD 插件&#xff0c;这些插件可以为 UI/UX 设计添加很酷的新功能&#xff0c;极大提升你的工作效率和产出。让我…

Linux 常用基本命令

1.走近Linux系统 开机登录 开机会启动许多程序。它们在Windows叫做"服务"&#xff08;service&#xff09;&#xff0c;在Linux就叫做"守护进程"&#xff08;daemon&#xff09;。 关机 在linux领域内大多用在服务器上&#xff0c;很少遇到关机的操作。毕竟…

大模型深挖数据要素价值:算法、算力之后,存储载体价值凸显

文 | 智能相对论 作者 | 叶远风 18.8万亿美元&#xff0c;这是市场预计2030年AI推动智能经济可产生的价值总和&#xff0c;其中大模型带来的AI能力质变无疑成为重要的推动力量。 大模型浪潮下&#xff0c;业界对AI发展的三驾马车——算力、算法、数据任何一个维度的关注都到…

23 mysql index 查询

前言 这里主要是 探究一下 explain $sql 中各个 type 诸如 const, ref, range, index, all 的查询的影响, 以及一个初步的效率的判断 这里会调试源码来看一下 各个类型的查询 需要 lookUp 的记录 以及 相关的差异 此系列文章建议从 mysql const 查询 开始看 测试表结构…

ubuntu 20 安装 CUDA

1. 查看需要安装的cuda版本 nvidia-smi cuda的版本信息如下图所示 2. 去官网下载对应版本的CUDA 官网&#xff1a;CUDA Toolkit Archive | NVIDIA Developer 弹出以下界面&#xff0c;依次点击以下按钮 得到以下内容&#xff1a; 复制下载链接&#xff0c;下载cuda11到本…

适用于 ONLYOFFICE 的智谱 AI 插件现已发布

很高兴向您介绍智谱 AI 插件&#xff0c;现已在我们的插件市场上线&#xff01;它是开源之夏 (OSPP) 计划的成果&#xff0c;由专注投入的参与者林剑波同学开发。智谱 AI 实质上与 ChatGPT 插件功能相同&#xff0c;但它是为与中国的 AI 无缝协作而量身打造。 关于智谱 AI 这款…

Linux系统编程(1)

父子进程通过两个管道进行通信。 伪代码 #include <unistd.h> void client(int, int), server(int, int);int main(int argc, char** argv) {int pipe1[2], pipe2[2];pid_t childpid;Pipe(pipe1);Pipe(pipe2);if ((childpid Fork()) 0) {// childClose(pipe1[1]);Close…

LeetCode 盛最多水的容器 双指针

原题链接&#xff1a; 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题面&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与…

uni-app:canvas-绘制图形2

效果 代码 <template><view><!-- 创建了一个宽度为300像素&#xff0c;高度为200像素的canvas元素。canvas-id属性被设置为"firstCanvas"&#xff0c;可以用来在JavaScript中获取该canvas元素的上下文对象。 --><canvas style"width:200px…

NPDP和PMP证书有啥区别?建议考哪个?

最近分享了很多项目经理和产品经理的问题&#xff0c;有宝子疑问关于这两个职位最热门的证书——PMP和NPDP究竟有什么区别&#xff1f;如何判断自己应该选择哪个&#xff1f;今天胖圆从证书性质&#xff0c;适合人群以及相关考试信息来给大家解读一下&#xff0c;两者有什么不同…

魔兽世界安装插件后进游戏闪退的一个原因。

最近体验了几个私服的WOW&#xff0c;在找插件的时候&#xff0c;总是会遇到wow群里老哥问一个经典的插件问题&#xff0c;进游戏后提示The user interface is using more than 48MB of memory.Set Script Memory to 0 in the character selection screen;然后有个倒计时&#…