JVM详细教程
JVM
前言
还在完善中先发布
 JVM虚拟机厂家多钟多样,具体实现细节可能不一样,这里主要讲的是虚拟机的规范,以下内容融合了各个平台发布的内容和周志明老师的《深入理解java虚拟机》
JVM概述
如何理解jvm跨平台?
编译成汇编代码的语言,例如C语言,编译后的二进制文件会因为操作系统的CPU和操作位数的不同无法做到通用。编译成.class的语言,不用关注操作系统的异同,不同的平台安装不同的JVM,代码层面不需要考虑操作系统的异同。JVM是解释运行.class文件的虚拟机,不止针对java。

jvm虚拟机产品
HotSpot VM
 KVM(Kilobyte)
 JRockit
JVM内存结构规范
下图只是JVM内存结构的规范,具体的JVM产品实现方案可能有所不同
 
java代码编译的过程

通过反射了解类是如何加载的
最终调用一个本地方法库函数forName0,获取Class<?>,同时传入了一个默认的ClassLoader类
 
 
 
ClassLoader
java的核心组件,所有的class都通过ClassLoader加载进入内存。ClassLoader通过读取字节码的二进制数据流到JVM当中,JVM再进行连接初始化。可以自定义ClassLoader读取指定的字节码文件,在这个过程中我们就可以对这个二进制流做相应的操作。加载的字节码可以在本地,jar包内,远程。
一些核心的ClassLoader类举例:
 BootStrapClassLoader:加载核心库java.*
 ExtClassLoader:加载扩展库javaX.*
 AppClassLoader:加载程序所在目录
 自定义ClassLoader:定制化加载
 
自定义一个ClassLoader了解双亲委派机制
一句话就是不断去父类找,看那个父类加载过这个字节码,有就从父类返回,没有就从子类读取
 好处:系统不用重复加载字节码
 
重写ClassLoader的步骤
1.读取二进制流返回给findClass()
 2.加载二进制流loadClass()
public class MyClassLoader extends ClassLoader {public static void main(String[] args) throws ClassNotFoundException {MyClassLoader myClassLoader = new MyClassLoader("/Users/alexyuan/Documents/codefile/giteemycode/mylearnrepository/jvmdemo/src/main/java/com/alexyuan/test/");Class<?> aClass = myClassLoader.loadClass("Test");System.out.println(aClass.getClassLoader());System.out.println(aClass.getClassLoader().getParent().getClass().getName());System.out.println(aClass.getClassLoader().getParent().getParent().getClass().getName());System.out.println(aClass.getClassLoader().getParent().getParent().getParent());}private String path;public MyClassLoader(String path) {this.path = path;}public MyClassLoader(String path, ClassLoader parentClassLoader) {super(parentClassLoader);this.path = path;}@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {// 先调用父类的loadClass方法Class<?> clazz = super.loadClass(name);// 自定义的类加载逻辑return clazz;}/*** 重写父类的findClass方法,在ClassLoader在执行 loadClass 方法时,* 如果父加载器不会加载类,就会调用当前重写的方法进行加载类*/@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {BufferedInputStream bis = null;ByteArrayOutputStream baos = null;try {bis = new BufferedInputStream(new FileInputStream(path + name + ".class"));baos = new ByteArrayOutputStream();int len;byte[] data = new byte[1024];while ((len = bis.read(data)) != -1) {baos.write(data, 0, len);}//获取内存中的完整的字节数组的数据byte[] classByteArray = baos.toByteArray();//将字节数组转换为Class的实例return defineClass(null, classByteArray, 0, classByteArray.length);} catch (IOException e) {e.printStackTrace();} finally {try {if (null != baos) {baos.close();}} catch (IOException e) {e.printStackTrace();}try {if (null != bis) {bis.close();}} catch (IOException e) {e.printStackTrace();}}return null;}
}
 
读取字节码文件,查看父类都有哪些

 BootstrapClassLoader:Java的启动类加载器,负责加载JRE的核心类库和启动时需要的类。
 ExtensionClassLoader:Java的扩展类加载器,负责加载JRE的扩展类库和用户自定义的扩展类库。
 SystemClassLoader:Java的系统类加载器,负责加载用户类路径中的类和资源。
 URLClassLoader:基于URL的类加载器,可以从指定的URL列表中加载类和资源。
 CustomClassLoader:自定义的类加载器,可以根据自己的需求实现自定义的类加载逻辑。

类的加载过程
1.加载:此阶段由类加载器从指定的位置加载类的二进制数据,包括从JAR文件、目录、网络等位置加载。在加载阶段,类加载器需要解析类的名称、父类、接口、方法、字段等元素,并将其转换为JVM可以识别的字节码格式。
2.链接:此阶段由JVM对字节码进行验证、准备和解析。验证阶段会验证字节码是否符合JVM的规范,包括验证类的名称、父类、接口、字段、方法等元素;准备阶段会为类变量分配内存,并设置默认初始值;解析阶段会解析类中的静态变量、方法和类的调用关系。
3.初始化:此阶段会初始化类中的静态变量和静态方法,并为类变量分配内存。在初始化阶段,如果类中存在静态代码块,会先执行静态代码块;如果类中存在静态方法,会先执行静态方法。在初始化阶段,JVM会为类变量分配内存,并将其初始化为默认初始值。
加载方式
隐示加载:new一个类初始化到内存中
 显示加载:Class.forName(),loadClass()
 显示加载的区别:
 loadClass()只到加载过程

 forName默认初始化是true,所有使用forName该类已经到初始化阶段,会运行类中的静态代码块
 
        MyClassLoader myClassLoader = new MyClassLoader("/Users/alexyuan/Documents/codefile/giteemycode/mylearnrepository/jvmdemo/src/main/java/com/alexyuan/test/");Class<?> aClass = myClassLoader.loadClass("Test");Class<?> aClass1 = Class.forName("/Users/alexyuan/Documents/codefile/giteemycode/mylearnrepository/jvmdemo/src/main/java/com/alexyuan/test/Teat.class");Object o = aClass1.newInstance();
 
java的内存模型
计算机内存
内存模型:
 计算机的内存模型是指计算机内部存储数据的方式和结构。计算机的内存模型通常分为三个部分:寄存器、主存储器和缓存。
寄存器:寄存器是CPU中的一组高速缓存,用于存储指令、数据和控制信息。寄存器的访问速度非常快,但是容量有限,只能存储少量的数据。
 主存储器:主存储器是计算机中的主要存储器,用于存储大量的数据和指令。主存储器的访问速度比寄存器慢,但是容量大,可以存储大量的数据。
 缓存:缓存是计算机中的一种高速缓存技术,用于缓存主存储器中的部分数据,以提高访问速度。缓存的容量通常比主存储器小,但是访问速度非常快。
 计算机的内存模型是指将数据和指令从主存储器中加载到寄存器和缓存中,并在CPU中进行处理和运算的过程。在计算机的内存模型中,数据和指令的访问速度取决于它们所存储的位置,从寄存器到主存储器再到缓存,访问速度逐渐变慢。因此,在编写高效的程序时,需要考虑如何优化数据和指令的访问方式,以提高程序的执行效率。
计算机内存读取寻址过程:
 
 操作系统提供的可寻址空间
 32位:2^32 4Gb的寻址范围
 64位:2^64的寻址范围
计算机地址空间划分:
 内核空间和用户空间是计算机操作系统中的两个概念,它们用于划分计算机内存空间的不同部分。
内核空间:内核空间是计算机内存空间的一部分,用于存储操作系统的核心程序和数据。内核空间是计算机操作系统的核心,它负责管理和控制计算机硬件资源,例如处理器、内存、磁盘、网络等。内核空间的访问权限非常高,只有操作系统本身才能访问。
用户空间:用户空间是计算机内存空间的另一部分,用于存储用户程序和数据。用户空间是用户程序的运行环境,它提供了一组基本的系统调用接口,用于用户程序与内核空间进行交互。用户空间的访问权限相对较低,只有用户程序才能访问。
在计算机操作系统中,内核空间和用户空间是通过内存保护机制实现的。内核空间和用户空间之间存在一个内存保护屏障,用于隔离内核空间和用户空间的数据和指令。只有操作系统本身才能通过内存保护屏障,从而访问内核空间和控制硬件资源。而用户程序只能通过系统调用接口,从而访问用户空间和执行操作系统提供的基本服务。
Java在JVM当中运行内存模型
1

私有区域
程序计数器(逻辑)(Program Counter Register)
为什么它是线程私有的?当多线程运行,切换线程的时候如何知道线程自己的字节码运行到什么地方,程序计数器的作用就是如此:
 1.记录线程自己的字节码运行到哪一行,因此是线程私有的
 2.既然记录的行号,那么就可以改变程序计数器中的值让这个线程去选择读取什么地方下一行的数据
java虚拟机栈(Stack)
java方法执行的内存模型,从局部变量表中取数据,在这个栈内存中通过出栈和入栈的方式进行方法的执行
 由多个栈帧组成
 栈帧包含:局部变量表(local variable),操作栈(Operand Stack),动态链接(Dynamic Linking),返回地址(Return Address)…等组成
 
本地方法栈
和虚拟机栈类似,运行的是native本地方法
局部变量表、操作数栈、程序计数器的关系

java为什么会栈内存溢出?
从上面线程虚拟方法栈就可以看出每调用一个方法就会有一个栈帧压栈,例如递归等方法,如果递归的层数太深,不断压栈,超过了栈的大小就会出现内存溢出
共享区域
堆(heap)
存放几乎所有的对象实例和数组,所有线程的共享区域。垃圾回收机制也就是针对堆内存的回收,因此也被称为GC堆
方法区(Method Area)
存储已被虚拟机加载的类型信息,常量,静态变量,JIT编译后的代码缓存数据等。
运行时常量池(Runtime Constant Pool)
2运行时常量池(Runtime Constant Pool):是方法区的一部分。Class文件中除了有类的版本、字 段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生 成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
 在jvm规范中,方法区除了存储类信息之外,还包含了运行时常量池。这里
 首先要来讲一下常量池的分类
 常量池可分两类:
 1、Class常量池(静态常量池)
 2、运行时常量池
 3、字符串常量池(没有明确的官方定义,其目的是为了更好的使用
 String ,真实的存储位置在堆)
对象
对象内存布局

 
jvm调优
目的
解决生产环境中日志不输出,死锁,cpu占用过高,如何分配线程数等问题,在于让程序跑起来也让程序跑的更快。
 
JVM参数分类
根据jvm参数开头可以区分参数类型,共三类:“-”、“-X”、“-XX”,
 标准参数“-”:每种类型的Jvm都会实现,-help,-version
 非标准参数“-X”:默认Jvm实现这些功能,但不是一定完全实现,-Xms,-Xmx等
 非Stable参数“-XX”:不稳定随着版本的不一致,参数也不一致
-X参数

 ■ -Xms20m :设置jvm初始化堆大小为20m,一般与-Xmx相同避免垃圾回收完成后jvm重新分。
■ -Xmx20m:设置jvm最大可用内存大小为20m。
■ -Xmn10m:设置新生代大小为20m。
■ -Xss128k:设置每个线程的栈大小为128k。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LZzqV4eD-1692237885248)(assets/image-20230615150410277.png)]](https://img-blog.csdnimg.cn/64e0e85e852b4b2280fb92041783ae4b.png)
-XX参数
Java -XX:+PrintFlagsFinal -version #打印系统XX参数
 
-XX:+PrintGCDetails:打印GC详情;
-XX:+PrintGCTimeStamps:打印时间戳;
■ -XX:CMSInitiatingOccupancyFraction=80 CMS gc,表示在老年代达到80%使用率时马上进行回收;
■ -verbose:gc:可以输出每次GC的一些信息;
■ -XX:-UseConcMarkSweepGC:使用CMS收集器;
GC信息查看
打印GC简单信息
-verbose:gc
-XX:+PrintGC
打印详细GC信息
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
指定GC日志以文件输出
-Xloggc:./gc.log
使用jps和jinfo查看java进程运行状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P5a4EsQL-1692237885248)(assets/ wps1.jpg)]
Jvm运行模式设置
Server模式性能强,64位默认为该模式。Client模式性能较弱,32位系统可以使用该模式。
1.7内存模型介绍

执行过程:eden区域满了将进入survivor去,survivor区未被回收的对象转移到tenured区域,tenured的没有回收的对象进入永久区。
Survivor区结构:两个相同的survivor区构成。运行时候只会使用一个,另外一个用做gc回收机制时复制对象使用。
Perm:永久区一般存储class和file。一段时间tenured没有被回收将会进入这个区域。
1.8内存模型介绍

 1.8版本取消永久区,使用元素区代替,元素区为本机内存不再jvm当中。
1.8版本jvm对内存组成

 Young区:两个survivor区+eden
MetaSpace:ccs+codecache
Jstat查看堆内存使用情况
命令可使用的参数
 
命令格式:jstat –{选项} 进程id 间隔时间 查询次数
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eD5FEMDn-1692237885249)(assets/wps6.jpg)]](https://img-blog.csdnimg.cn/bed62f1651e84eaa89075eaf764df3e3.jpeg)
Jmap使用对堆内存进行统计
Jmap参数
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-opzIylYq-1692237885249)(assets/截屏2023-06-15 15.27.06.png)]](https://img-blog.csdnimg.cn/707698c2ba6a481da4a514f42662abc7.png)
Mat工具对jdump文件分析
- 将内存情况保存为“.dat”文件
 - 使用mat打开文件
 
使用Jstack查看当前jvm中运行现场的情况
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LjpkVE6J-1692237885250)(assets/wps8.jpg)]](https://img-blog.csdnimg.cn/f2e0772a68054c09a70db51e4ba41a78.jpeg)
线程状态介绍
初始态:刚刚启动的状态,也就是刚刚调用start()函数的状态
运行态:在CPU中运行
就绪:等待CPU资源就可执行
 阻塞:没有获得资源一直请求,超时后进入阻塞队列,当获取的资源之后进入就绪
等待态:需要获取的启动资源,属于被动等待
超时等待:主动进入等待状态,如sleep函数
终止态:线程运行结束
使用jmx查看内存和线程使用状况
在JDK中bin目录双击打开
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p1mbvham-1692237885250)(assets/wps9.jpg)]](https://img-blog.csdnimg.cn/7deca6b9df5947639429653d0b7cc447.jpeg)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7aZdoOwH-1692237885250)(assets/wps10.jpg)]](https://img-blog.csdnimg.cn/2d06224cf3c04c49bf6de9705acb6573.jpeg)
JVM——垃圾回收机制
什么是垃圾回收
程序在运行时需要申请内存,内存使用之后需要归还内存给系统,当一些无效对象一直占用内存就可能导致内存溢出,因此需要对无效对象进行垃圾回收。
垃圾回收算法
垃圾回收算法——引用计数算法
概述:每个对象都设置一个计数器,如果有对象引用它计数器进行加一,引用结束减一,系统对对象的计数器进行判断,如果计数器为0者回收该对象
缺点:无法回收循环引用,也就是只要是改对象被引用,这就不会被回收,无论这个引用是否指向null或者未被使用。
垃圾回收算法——标记清除法
概述:当系统做垃圾回收的时候暂停所有线程,遍历所有对象,标记处对象的引用关系,清楚root对象未被应用到的对象。
缺点:性能低,由于对象可能在不同内存中,回收的内存很可能不连续,也就是内存碎片化严重。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rjrpw0Rh-1692237885250)(assets/wps11.jpg)]](https://img-blog.csdnimg.cn/f0198c0345a34e698019692eb4272741.jpeg)
垃圾回收算法——标记压缩算法
概述:由标记清楚法演变而来,在回收之前将有效对象压缩在一个连续的内存再回收,这样解决了回收内存碎片化的问题
缺点:性能比优化之前更低
垃圾回收算法——复制算法
概述:将内存分为两块,一块使用,另一块闲置,当进行垃圾回收的时候将有效对象放在闲置内存当中,在将内存情况,两个内存空间交换角色,然后重复之前的操作
缺点:运行时有一块内存空间没有使用因此有点资源浪费
应用区域:young中的survivor由两块相同的内存空间构成就是使用的复制算法,这样垃圾回收的区域是完整的一块内存空间,没有碎片化。
回收算法总结
每一个算法都各有有点,根据不同区域的特性不同使用不同算法,年轻代对象少可以使用复制算法,gen区对象多适合标记清楚和标记压缩算法。
垃圾收集器以及内存分配
算法只是实现方式,在java内部提供了一些垃圾回收器,垃圾回收器去完成垃圾的回收。
串行收集器
只有一个线程执行收集器,一般不用
并行收集器
Parnew收集器
将串行收集器改成并行而来
ParallelGC收集器
在parnew的基础上增加了吞吐量的设置
CMS垃圾收集器
算法:标记清除算法
工作位置:老年带
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZKOPiidj-1692237885251)(assets/wps12.jpg)]](https://img-blog.csdnimg.cn/a8ceb1951caf45f98ea40281d89c6e95.jpeg)
Stw:线程全部暂停,stop world
标记时会触发stw
G1垃圾回收器
概述:取消了老年带,年轻代的概念,清理工作是将对象从一个区复制到另一个区。G1为因为巨形对象在拷贝的时候对回收器性能影响很大,因此具有一个humongous区域。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HbbwAd1N-1692237885251)(assets/wps13.jpg)]](https://img-blog.csdnimg.cn/0d06f20fda6b47dabe0e492a5f6a1a09.jpeg)
G1垃圾回收器使用流程
第一步:打开G1作为垃圾回收器
第二步:设置最大停顿时间,也就是标记清除的时候
第三步:设置堆最大内存
YoungGC
对年轻带进行GC,eden空间向survivor空间复制转移,也向old区转移
MixGC
主要GCyoung区,也GCold区
G1垃圾回收如何找到根对象
使用remember set方式,就是每个空间初始化的时候生成一个set集合,这个集合记录这片空间被引用的空间,通过这些set集合找到根对象,然后从
使用G1垃圾回收器
1.jvm参数:
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100
-Xmx256m
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-XX:+PrintHeapAtGC
-Xloggc:E://test//gc.log
GC历史文件在:E://test//gc.log目录下,打开https://gceasy.io/文件查看吞吐量
参考文献
《深入理解java虚拟机:周志明》 ↩︎
《深入理解java虚拟机:周志明》 ↩︎
相关文章:
JVM详细教程
JVM 前言 还在完善中先发布 JVM虚拟机厂家多钟多样,具体实现细节可能不一样,这里主要讲的是虚拟机的规范,以下内容融合了各个平台发布的内容和周志明老师的《深入理解java虚拟机》 JVM概述 如何理解jvm跨平台? 编译成汇编代码…...
Smartbi吴华夫:后疫情时代,BI发展趋势的观察与应对
沿着旧地图找不到新大陆,“基于指标体系的可视化分析和增强分析”成为BI发展新阶段。Smartbi V11系列新品与时俱进,以指标为核心,同时融合BI应用,赋能管理者和业务,成为引领数字化运营的新航标! ——思迈特…...
软件设计模式系列之三———工厂方法模式
1 模式的定义 工厂方法模式是一种常见的设计模式,属于创建型设计模式之一,它在软件工程中用于对象的创建。该模式的主要思想是将对象的创建过程抽象化,将具体对象的实例化延迟到子类中完成,以便在不同情况下可以创建不同类型的对…...
pytorch 多卡分布式训练 调用all_gather_object 出现阻塞等待死锁的问题
pytorch 多卡分布式训练 torch._C._distributed_c10d中的函数all_gather_object 出现阻塞等待死锁的问题 解决办法就是 在进程通信之前调用torch.cuda.set_device(local_rank) For NCCL-based processed groups, internal tensor representations of objects must be moved …...
SpringMvc增删改查
SpringMvc增删改查 一、前期准备二、逆向生成增删改查2.2.aspect切面层2.3.Mybatis generator逆向生成2.4.根据生成代码编写Biz层与实现类 三、controller层代码编写四、前台代码与分页代码五、案例测试 一、前期准备 1.2.导入pom.xml依赖 <?xml version"1.0" …...
【计算机网络】网络编程接口 Socket API 解读(5)
Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。 本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。…...
手动实现一个bind函数!
原文地址:手动实现一个bind函数! - 知乎 1.bind函数用法 bind()方法用于创建一个新的函数,这个新函数接收的第一个参数代表的就是this,利用bind()函数我就就可以任意改变函数内部的this指向了。 官网的解释: bind()…...
数据结构-时间复杂度/空间复杂度
Hello,好久没有更新了哦,已经开始学习数据结构了,这篇文章呢就是对刚学数据结构所接触到的时间复杂度进行一个分享哦,如果有错误之处,大家记得拍拍我哦~ 既然要讨论时间/空间复杂度,那我们就得知道时间/空…...
英语写作中“展示”、“表明”demonstrate、show、indicate、illustrate的用法
一、demonstrate、show、indicate在论文写作中主要用法是:demonstrate/show/indicate 从句: Sb./Sth. demonstrates/shows/indicates that ……从句中一般表达事实、观点和结论等。 例句: The authors demonstrated/showed/indicated that…...
Redis的java客户端
在Redis官网中提供了各种语言的客户端,地址:https://redis.io/resources/clients/ redis的java客户端 https://redis.io/resources/clients/#java 1.jedis使用 引入依赖 <dependency><groupId>redis.clients</groupId><artifac…...
Android环境配置笔记
文章目录 一、各环境文档二、参考 一、各环境文档 Gradle官方的兼容性文档:Java Compatibility 更新日期:2023.9.12 Android Gradle插件版本:Android Gradle Plugin 二、参考 参考文章:Android问题记录...
element-table 行的拖拽更改顺序(无需下载sortableJs
样例展示:vueelement 通过阅读element文档我们发现element并不提供拖拽相关的api 本博客通过element提供的行类名 注册函数 实现行与行的拖拽 1.设置el-table 的行样式类名 这里是用的是 function <el-table:data"outputData":row-class-name&qu…...
Docker部署jenkins
目录 一、jenkins原理二、Docker部署jenkins1.下载jenkins镜像文件2.查看下载的jenkins镜像3.创建Jenkins挂载目录并授权权限4.创建并启动Jenkins容器5.查看jenkins是否启动成功6.查看docker容器日志7.配置镜像加速8.访问Jenkins页面,输入ip地址加上9000端口9.获取管…...
从0到1学会Git(第三部分):Git的远程仓库链接与操作
写在前面:前面两篇文章我们已经学会了git如何在本地进行使用,这篇文章将讲解如何将本地的git仓库和云端的远程仓库链接起来并使用 为什么要使用远程仓库:因为我们需要拷贝我们的代码给别人以及进行协同开发,就需要有一个云端仓库进行代码的存储和同步&a…...
虚拟机Ubuntu操作系统常用终端命令(1)(详细解释+详细演示)
虚拟机Ubuntu操作系统常用终端命令 本篇讲述了Ubuntu操作系统常用的三个功能,即归档,软链接和用户管理方面的相关知识。希望能够得到大家的支持。 文章目录 虚拟机Ubuntu操作系统常用终端命令二、使用步骤1.归档1.1创建档案包1.2还原档案包1.3归档并压缩…...
redis实战-redis实现异步秒杀优化
秒杀优化-异步秒杀思路 未优化的思路 当用户发起请求,此时会请求nginx,nginx会访问到tomcat,而tomcat中的程序,会进行串行操作,分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单 4、校验是否是一…...
Python爬虫-IP隐藏技术与代理爬取
前言 在进行爬虫程序开发和运行时,常常会遇到目标网站的反爬虫机制,最常见的就是IP封禁,这时需要使用IP隐藏技术和代理爬取。 一、IP隐藏技术 IP隐藏技术,即伪装IP地址,使得爬虫请求的IP地址不被目标网站识别为爬虫。…...
二刷力扣--链表
链表 链表类型: 单链表(可以访问后面的一个节点) 双链表(可以访问前后节点) 循环链表(最后一个节点指向首节点) 在Python中定义单链表节点: class ListNode:def __init__(self, v…...
返回值加const ,为了不拷贝得到成员的值,但被赋值的左值也要const
1. getA 函数返回值 什么都不加,也改不了c里面a的指针指向 why?返回成员变量时,会复制一下。 返回成员变量时,一般会赋值一下没有RVO_地摊书贩的博客-CSDN博客 2. getA 函数返回值 加了引用, 就没有复制 3. getA 函数…...
本地如何使用HTTPS进行调试
在现代前端开发中,HTTPS已经成为不可或缺的一部分,因为它在保护用户数据和确保网站安全性方面发挥着关键作用。然而,有时在本地开发过程中启用HTTPS可能会变得有些复杂。在本文中,我们将介绍如何轻松地在本地进行HTTPS调试&#x…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...
链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
