JVM原理-基础篇

Java虚拟机(JVM, Java Virtual Machine)是运行Java应用程序的核心组件,它是一个抽象化的计算机系统模型,为Java字节码提供运行环境。JVM的主要功能包括:类加载机制、内存管理、垃圾回收、指令解释与执行、异常处理与安全检查、性能优化等。

目录

一、初识JVM

1.1、JVM基础知识

1.2、JVM的组成部分

二、字节码文件详解

2.1、字节码文件的基本组成

2.2、类加载器

三、JVM的内存区域

四、JVM的垃圾回收机制

4.1、自动垃圾回收

4.2、方法区的回收

4.3、堆内存的回收


一、初识JVM

1.1、JVM基础知识

1.什么是JVM?

JVM是java虚拟机,本质上是运行在计算机上的程序,它的职责是运行Java字节码文件。

正常我们编写的是.java文件,通过javac进行编译成.class的字节码文件,然后由JVM进行加载并解释成为机器码。

2.JVM的三大功能?

JVM的第一个作用是类加载并对对字节码文件的指令进行解释成机器码。

JVM的第二个功能是内存管理,主要包括为对象分配内存,以及垃圾回收等。

JVM的第三个功能是即时编译,对热点代码进行优化,提升执行效率。

java语言是先编译成字节码文件,再通过jvm解释成可执行的机器码文件。C/C++是直接编译链接成可执行的.exe文件,所以一般来说C/C++语言的性能更高。

Java语言的实时解释主要是为了实现跨平台特性,相当于一次编译成字节码文件,可以不同的平台通过JVM进行解释运行。

3.常见的JVM有哪些?

常见的虚拟机有如下几种,其中HotSpot是JDK默认自带的虚拟机。

1.2、JVM的组成部分

JVM主要包括如下几部分:类加载器、运行时数据区、执行引擎、本地接口四个部分。

1.类加载器:加载class字节码文件中的内容到内存中。

2.运行时数据区:负责管理JVM所使用的内存,比如创建对象和销毁对象。

3.执行引擎:将字节码中的文件解释成机器码,同时使用即时编译器优化性能。

4.本地接口:调用本地已经编译的方法,比如虚拟机中提供的c/c++方法。

其中运行时数据区包括大部分:

  • 堆:存储对象实例和数组,是所有线程共享的一块区域,也是垃圾回收的主要区域。
  • 虚拟机栈:每个线程都有自己的栈空间,用于存放基本类型的变量、对象引用以及方法调用的上下文信息(如局部变量表、操作数栈等)。
  • 方法区:存储类元数据(如类的结构信息)、静态变量、常量池和即时编译后的代码等。
  • 程序计数器:记录当前线程执行字节码的位置。
  • 本地方法栈:为JNI调用的本地方法服务。

二、字节码文件详解

2.1、字节码文件的基本组成

注意:直接使用记事本打开字节码文件会是乱码,一般来说使用jclasslib工具可以查看字节码文件

字节码文件主要包含如下5个部分:

1.基础信息:魔数、字节码对应的Java版本号、访问标识、父类与接口。

2.常量池:保存了字符串常量、类或者接口名主要在字节码指令中使用。

3.字段:当前类或者接口声明的字段信息。

4.方法:当前类或者接口声明的方法信息。

5.属性:类的属性,比如源码的文件名、内部类的列表等。

2.2、类加载器

1.类的生命周期?

加载->连接(验证、准备、解析)->初始化->使用->卸载

加载:类加载器根据类的全限名通过不同的渠道以二进制流的方式获取字节码信息。类加载完成后JVM会把字节码信息放到方法区中。Java虚拟机还会在堆中生成一份与方法区中类似的java.lang.Class。

连接:验证阶段是验证内容是否满足java虚拟机规范,准备阶段是静态变量赋初值,解析阶段是将常量池中的符号引用替换成指向内存的直接引用。

验证:

1.对文件 格式的校验以及主次版本号是否满足当前Java虚拟机版本要求。例如:主版本号不允许超过运行环境的版本号,如果主版本号相等,副版本号也不能超过。

2.元信息验证,比如类必须有父类。

3.验证程序执行指令的语义。

4.符号引用验证,例如是否访问了其他类中private修饰的方法。

准备:

final修饰的基本数据类型的静态变量,准备阶段会对变量赋终值。

解析:

将常量池中的符号引用替换为直接引用。

符号引用:在字节码文件中使用编号来访问常量池中的内容。

直接引用:不再使用编号,使用内存中的地址进行具体数据的访问。

初始化:

初始化阶段会执行静态代码块中的代码,并为静态变量赋初值。本质上就是初始化阶段会执行字节码文件中cliniit部分的指令。

以下几种方式会导致类的初始化:

1.访问一个类的静态变量或者静态方法,注意final修饰的常量不会触发初始化 。

2.调用Class.forName()

3.new一个该类的对象时

4.执行Main方法中的当前类

2.常见的类加载器有哪些?

类加载器是Java虚拟机提供给应用程序去实现获取类或接口的字节码数据的技术。

启动类加载器(BootStrap ClassLoader):用于加载一些核心类,由HotSpot虚拟机提供,使用 C++编写的类加载器。

扩展类加载器器:用于加载一些扩展类,由JDK提供,使用Java编写的类加载器。

应用程序类加载器:用于加载应用第三方jar包里的类,由JDK提供,使用Java编写的类加载器。

3.双亲委派机制的作用,什么是双亲委派机制?

作用:通过双亲委派机制避免恶意代码替换JDK中的核心类库,确保核心类库的完整性和安全性,另外可以避免同一个类被多次加载。

双亲委派机制:类加载器在加载之前会向上查找其父类是否加载过,如果父类加载过则直接返回,父类能未加载过则判断能否加载(是否在类加载器的加载目录路径中),能加载就加载,不能加载则由子类加载。

4.如何打破双亲委派机制?为什么要打破双亲委派机制?

打破双亲委派机制的三种方式:
1.自定义类加载器并重写LoadClass方法,就可以把双亲委派机制的代码清除

2.利用上下文类加载器加载类,例如:JDBC和 JNDI等

3.利用Osgi框架的类加载器

  • 实现特殊的需求:在某些情况下,可能需要加载特殊的类或者自定义类加载逻辑,例如实现热替换(HotSwapping)功能,或者实现隔离的类加载环境,如OSGi、Tomcat容器等,这些场景下需要自定义类加载器并改变类加载的顺序和规则。
  • 实现版本隔离或多重类加载:在某些框架或应用服务器中,为了支持多个版本的同一类库共存,或者为了实现模块化加载,需要打破双亲委派,让每个模块拥有独立的类加载器来加载自己的类。

三、JVM的内存区域

内存溢出(OOM):程序在使用某一块内存区域时,存放的数据占用内存大小超出了虚拟机所能提供的最大内存上限。

1.Java的内存区域?

程序计数器(线程不共享):每个线程通过程序计数器记录当前要执行的字节码指令的地址。在程序执行过程中,程序计数器会记录下一行字节码指令的地址,执行完当前指令后,java虚拟机的执行引擎会根据指令计数器执行下一行 指令。具体来说程序计数器有两个作用:1.记录指令执行的地址并控制线程执行指令。2.多线程执行指令,线程切换时候用来记录线程执行到指令的地址。

程序计数器不会产生内存溢出,因为每个线程只是存储一个固定长度的内存地址。

Java虚拟机栈(线程不共享):Java虚拟机栈随着线程的创建而创建,随着线程的销毁而回收。java虚拟机栈存放的是栈帧,栈帧包含三部分:局部变量表、操作数栈、帧数据。

局部变量表:程序在运行过程中,存放执行方法的所有局部变量。局部变量表本质上是一个数组,数组中每个位置称为一个槽,long和double占2个槽,其它类型占1个槽。局部变量保存的内容:实例方法的this,方法的参数,方法体中声明的局部变量。为了节省空间,局部变量表的槽是可以复用的,一旦某个局部变量失效,当前的槽就可以被复用。

操作数栈:是虚拟机在执行指令的过程用来存放临时数据的一块区域。比如:当前指令的值压入操作数栈中,后面的指令可以弹出并使用该值。在编译时期就可以确定操作数栈的最大深度,从而在执行的时候正确分配内存大小。

帧数据:动态链接、方法出口、异常表的引用。动态链接用于保存符号引用到运行时常量池内存地址的一个映射关系。方法出口存放的是栈帧中下一个指令的执行地址。异常表存放的是代码中异常的处理信息,包括异常捕获的生效范围以及发生异常后跳转到字节码指令的位置。

要修改 Java虚拟机栈的大小,可以使用虚拟机参数-Xss,例如:-Xss256k

虚拟机HotSpot对栈的最大值与最小值有要求,例如:windows下jdk8的运行虚拟机栈的范围在180k-1024m之间。另外,局部变量过多或者操作数栈深度过大也可能影响栈内存的大小。

本地方法栈(线程不共享):和Java虚拟机栈类似,用于服务native方法。Java虚拟机栈存储的是Java方法调用时的栈帧,而本地方法栈存储的是native本地方法的栈帧。在HotSpot虚拟机中,Java虚拟机栈和本地方法栈使用同一块内存空间。

(线程共享):创建出来的对象存在堆内存中,堆内存的大小是有上限的,当一直向堆中放入对象达到上限之后就会抛出OutOfMemory(OOM)的错误。要修改虚拟机堆的大小可以使用参数:

-Xmx值(max最大值)  -Xms值(初始的total) 建议将这两个值设置为相同大小的,这样程序在启动的时候使用的总的内存就是最大的内存,无需向Java虚拟机再次申请,减少堆内存申请的开销。

方法区(线程共享):主要存放三部分的信息:1.类的基本信息,2.运行时常量池:字节码文件的常量池内容,3.字符串常量池内容。在类加载阶段,方法区会存放类的基本信息。JDK7及之前的版本将方法区放在堆内存中的永久代中,堆的大小由虚拟机控制;JDK8及之后的版本将方法区放到了元空间中,元空间位于操作系统维护的直接内存中,默认只要不超过操作系统承受的上限,则可以一直分配。运行时常量池主要用于存储编译期生成的各种字面量和符号引用。字符串常量池主要用于存储字符串字面量的对象引用地址的一个区域。

注意:String类型的字符串,如果是变量拼接,则转换成StringBuilder,如果是常量拼接,则直接拼接。

直接内存:JDK8及其以后方法区就存在直接内存的元空间中。

四、JVM的垃圾回收机制

4.1、自动垃圾回收

内存泄漏:指的是不再使用的对象在系统中未被回收,内存泄漏的累积可能会导致内存溢出。

在C/C++这类语言中没有自动垃圾回收机制,一个对象不再使用,需要手动释放,否则会导致内存泄漏 。

Java为了简化对象的释放,引入了自动垃圾回收机制,通过垃圾回收器来对不再使用的对象进行回收,垃圾回收器主要是对堆上的内存进行回收。

4.2、方法区的回收

我们知道类的声明周期包括:加载,连接(验证,准备,解析),初始化,使用,卸载五个部分,其中最后一步的卸载就是方法区的回收。

判断一个类是否可以被卸载需要同时满足以下三个条件:

1.此类的所有实例对象都已经被回收,在堆中不存在该类的任何实例对象以及子类对象。

2.加载该类的类加载器已经被回收。

3.该类对应的java.lang.Class对象在任何地方都没有被引用。

如果需要手动回收垃圾,需要使用 System.gc()方法

4.3、堆内存的回收

1.常见的垃圾回收算法?

引用计数法与可达性分析法

引用计数法:为每个对象维护一个引用计数器,当对象被应用则加1,取消引用则减1。该方法优点是十分简单。缺点:存在循环引用的问题,A引用B且B也引用A,假如应用程序不再需要这两个对象,但是 引用 计数器不为0,所以导致这两个对象无法回收,会出现内存泄漏。


可达性分析法:Java使用的是可达性分析算法来判断对象是否可以回收,可达性分析将对象分为两类:垃圾回收的根对象(GC Root)与普通对象,对象与对象之间存在引用关系。如果从普通对象到根对象的引用链是不可达的,则说明该对象则是可回收的。

那么哪些对象可以被称为是GCRoot对象呢,以下四类可以被称为垃圾回收根对象:
1)线程Thread对象

2)系统类加载器加载的 java.lang.Class对象

3)监视器对象,用来保存同步锁synchronized关键字持有的对象

4)本地方法调用时使用的全局对象

标记清除法:在可达性分析算法确定了哪些对象是可达(存活)之后,垃圾收集器将对那些不可达的对象进行标记操作。标记完成后,垃圾收集器会清除所有被标记为不可达的对象占用的内存空间。优点:实现简单,第一阶段进行标记,第二阶段进行清除即可。缺点:内存碎片化,清除掉一些碎片的内存可能导致无法再分配空间,维护链表进行分配,分配速度慢。

标记复制法:当前存活的对象复制到另一块空间,将当前的空间进行清理掉。优点:吞吐量高,复制后不会发生碎片化。缺点:内存空间的使用率低 。

标记压缩法:也称为标记整理算法,使用可达性分析标记存活的对象,将存活的对象移动到内存的一侧,清理掉存活对象之前的内存空间。优点:内存使用率高,不会产生碎片化。缺点:整理算法的效率不高。

分代GC算法:分代垃圾回收将整个内存区域划分成年轻代与老年代。

年轻代:该区域包含三个部分:伊甸园区Eden,幸存者区S0,幸存者区S1。

创建出来的对象首先会放入伊甸园区,如果Eden区满了,就会触发young GC,如果可以被回收,则回收,否则放入幸存者区,如果年轻代的对象一直没回收,存活时间比较长的对象会被放入到老年代。当老年代不足的时候,且年轻代也满了,无法放入新的对象就会触发 full GC。

2.常见的垃圾回收器?

为什么分代GC算法要把堆内存空间 划分成年轻代与老年代?

因为年轻代用于存放可以很快被回收的对象,比如:用户订单数据。老年代则存放长期存活的对象,比如 Spring的大部分Bean对象。在虚拟机的默认设置中,新生代的大小 要远小于老年代的大小。总的来说,分代GC算法将堆分成新生代和老年代的主要原因可以分为如下三点:

1.可以通过调整年轻代和老年代的比例来适应不同类型的应用程序,提高内存的利用率和性能。

2.新生代和老年代选择不同的垃圾回收算法,新生代一般选择标记复制法,老年代一般选择标记清除法与标记压缩法,由程序员来选择,灵活度较高。

3.分代的设计只允许回收新生代,如果能满足对象分配的要求就不需要对整个堆进行回收,即不需要full GC。

常见的垃圾回收器:Serial、ParNew、Parallel Scavenge、CMS、Serial Old、Parallel Old

Serial是一种单线程串行的年轻代垃圾回收器,使用的是标记复制法,适用于单cpu进行处理垃圾回收,不适用于多cpu下的处理,多cpu下可能会使得其它用户线程处于长时间的等待状态。

SerialOld是Serial的老年代版本,采用单线程串行回收,可以与Serial垃圾回收器搭配使用。

ParNew是年轻代的垃圾回收器,本质上是堆Serial进行多cpu下的优化,使用多线程进行垃圾回收,与老年代垃圾回收器CMS进行搭配使用。

CMS垃圾回收器关注的是系统的暂停时间,允许用户线程和垃圾回收线程在某些步骤中同时进行,减少了用户线程的等待时间。采用标记清除法,垃圾回收停顿的时间短,用户体验好,但是存在内存碎片化如果老年代内存不足会退化成单线程SerialOld回收。CMS适用于请求数据量大,频率高的场景,例如:订单接口、商品接口等。

Parallel Scavenge垃圾回收器:是JDK8默认的年轻代垃圾回收器,多线程并行回收,关注的是系统吞吐量,具备自动调节堆内存大小的特点。吞吐量高,但是不能保证单次的停顿时间,适用于后台任务,比如:大数据的处理、大文件的导出等。

Parallel Old垃圾回收器:是为Parallel Scavenge设计的老年代的垃圾回收器,利用多线程并发收集,一般来说,使用Parallel Old+Parallel Scavenge组合,不需要设置堆内存的最大值,垃圾回收器会根据最大暂停时间和吞吐量自动调整堆内存的大小。

当发生STW时,JVM会暂停所有非垃圾收集线程(即除GC线程之外的所有用户线程),STW事件会导致应用程序暂时失去响应,对于实时性要求高的应用来说,STW时间过长可能会对系统性能造成显著影响。

G1垃圾回收器:是年轻代和老年代的垃圾回收器,JDK9开始之后默认的垃圾回收器,G1垃圾回收器是结合了CMS垃圾回收器与Parallel Scavenge垃圾回收器的优点,具备以下三个优点:1.支持大的堆空间的回收,并有较高的吞吐量。2.支持多CPU并行垃圾回收。3.允许用户设置最大暂停时间。

G1的整个堆会被划分成多个大小相等的区域,区域不要求连续,具体分为:伊甸园区、幸存者区、老年代区。G1的垃圾回收有两种方式:年轻代回收(young GC),回收伊甸园区和幸存者区不用的对象,年轻代不足,会触发young GC,使用标记复制法进行垃圾清理。

当某个对象被复制多次,存活年龄达到阈值15,该对象将会被移入老年代,多次回收后,会出现很多的老年代区,此时总堆的占有率达到阈值,此时会采用标记复制法回收年轻代与老年代的对象。G1老年代的清理会选择存活度最低的区域进行回收,可以保证回收效率最高。如果发现没有足够的区域存放转移的对象,会触发full GC,单线程执行标记整理算法,会导致用户线程的暂停。

3.Java中四种引用方式?
强引用:通过可达性分析判断,对象被引用则不是垃圾,若对象到GCRoot不可达,可以认为是垃圾,会被回收掉。当内存不足的时候,只有对象被引用,就不会被回收。

软引用:当程序内存不足的时候,软引用对象会被回收掉。SoftReference类来实现软引用。软引用对象回收后,内存仍然不足可能会报OOM。

弱引用:使用弱引用的对象,再使用完成后无论是否存在引用都会被回收掉。弱引用使用WeakReference类来实现,弱引用主要在ThreadLocal中使用。

虚引用:虚引用的作用是对象被垃圾回收器回收的时候可以收到相应的通知。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[每周一更]-(第89期):开源许可证介绍

开源代码本就是一种共享精神,一种大无畏行为,为了发扬代码的魅力,创造更多的价值,让爱传递四方,让知识惠及更多人; 写文章也是一种共享精神,让知识传播出去。 介绍下开源中不同许可证的内容限…

【leetcode】随机链表的复制

大家好,我是苏貝,本篇博客带大家刷题,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 点击查看题目 思路: struct Node* copyRandomList(struct Node* head) {struct Node* curhead;//1.copy原链…

【矩阵】【方向】【素数】3044 出现频率最高的素数

作者推荐 动态规划的时间复杂度优化 本文涉及知识点 素数 矩阵 方向 LeetCode 3044 出现频率最高的素数 给你一个大小为 m x n 、下标从 0 开始的二维矩阵 mat 。在每个单元格,你可以按以下方式生成数字: 最多有 8 条路径可以选择:东&am…

Nginx基础知识

文章目录 简介安装Ubuntu安装CentOS安装windows 常用命令配置文件 nginx.confnginx -V 反向代理 & 负载均衡 简介 Web服务器,高性能,Http与反向代理的服务器。启动后浏览器输入 http://localhost/ 显示欢迎页面就是启动成功了。在nginx安装目录下cm…

【AntDesign】解决嵌套section或layout中,h1字体比h2小问题

问题&#xff1a;以下情况均会导致h1比h2小&#xff0c;具体原因是浏览器默认样式里面&#xff0c;对h1不同层级设置了特殊的样式&#xff0c; <section class"css-dev-only-do-not-override-12q8zf4 ant-layout"><section class"css-dev-only-do-not…

THINKPHP 跨域报错解决方案

报错&#xff1a;has been blocked by CORS policy: Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header is present on the requested resource. 环境&#xff1a;thinkphp6 nginx 今天和VUE配合调用接口的时候发现跨…

Maven-私服(黑马学习笔记)

前面我们在讲解多模块开发的时候&#xff0c;我们讲到我们所拆分的模块是可以在同一个公司各个项目组之间进行资源共享的。这个模块的资源共享&#xff0c;就需要通过我们接下来所讲解的Maven的私服来实现。 首先我们先介绍一下什么是私服&#xff0c;以及它的作用是什么。再来…

瑞吉苍穹外卖如何拓展?已经经过不同公司多轮面试。项目中会问到哪些问题?以及问题如何解决?

别催了&#xff0c;别催了&#xff0c;先收藏吧。 作者大大正在加班加点完成。 文章会尽快发布&#xff0c;关注收藏&#xff0c;尽请期待。 想要加入并查阅作者的知识库可以联系作者 不要白嫖&#xff0c;通过后&#xff0c;附上关注和收藏截图。 已有众多小伙伴加入 目前…

mysql读写分离方案

什么是读写分离&#xff1f; 读写分离就是将对数据库的读操作和写操作分散到不同的数据库节点上 如何实现读写分离&#xff1f; 因为更多的读多写少&#xff0c;所以为了缓解主库的读能力从而引入了从库&#xff0c;这样就可以减少主库的负担&#xff0c;从而解决了应用的并发…

【教程】移动互联网时代的APP上架流程和要点

目录 摘要 引言 正文 一、应用商店注册 二、准备APP材料 三、打包上传App 摘要 本文将介绍移动应用程序上架的基本流程和要点&#xff0c;包括应用商店注册、APP材料准备、打包上传App、APP审核以及发布APP的详细步骤。此外&#xff0c;还会提到利用appuploder工具简化i…

【JavaScript】面试手撕节流

引入 上篇我们讲了防抖&#xff0c;这篇我们就谈谈防抖的好兄弟 – 节流。这里在老生常谈般的提一下他们两者之间的区别,顺带给读者巩固下。 PS: 开源节流中节流与这个技术上的节流&#xff0c;个人认为本质上是一样的。 开源节流的节流指的是节省公司的金钱开支。前端技术上的…

Windows的Docker-Desktop安装与问题总结

目录 Docker-Desktop安装步骤 环境配置 Docker-Desktop安装问题总结 问题1&#xff1a;docker-desktop setting界面一直加载转圈 问题2&#xff1a;docker镜像的存储位置变更&#xff08;防止C盘空间不足&#xff09; 参考文献&#xff1a; Docker-Desktop安装步骤 环境…

Unity(第十八部)物理力学,碰撞,触发、关节和材质

1、重力 刚体组件 英文中文描述RigidBody刚体组件physics->rigidbody &#xff0c;刚体组件使一个物体有了质量&#xff0c;重力等。&#xff0c;use gravity 勾选后&#xff0c;物体才会受到重力&#xff0c;会自动下落&#xff0c;取消勾选就不会。&#xff0c;&#xf…

计算机网络物理层知识点总结

本篇博客是基于谢希仁编写的《计算机网络》和王道考研视频总结出来的知识点&#xff0c;本篇总结的主要知识点是第二章的物理层。上一章的传送门&#xff1a;计算机网络体系结构-CSDN博客 通信基础 物理层概念 物理层解决如何在连接各种计算机的传输媒体上传输数据比特流&am…

ElasticSearch搜索引擎使用指南

一、ES数据基础类型 1、数据类型 字符串 主要包括: text和keyword两种类型&#xff0c;keyword代表精确值不会参与分词&#xff0c;text类型的字符串会参与分词处理 数值 包括: long, integer, short, byte, double, float 布尔值 boolean 时间 date 数组 数组类型不…

汽车三元催化器的废品项目详解,三元催化再生项目的回收技术教学

一、教程描述 这是一个收废品项目&#xff0c;就收那些别人不懂的&#xff0c;三元催化器的附加值高&#xff0c;只要掌握技术&#xff0c;怎么玩都行的&#xff0c;只是要放得下你的面子。三元催化器&#xff0c;是安装在汽车排气系统中最重要的机外净化装置&#xff0c;它可…

CodeWhisperer安装教导--一步到位!以及本人使用Whisperer的初体验。

CodeWhisperer是亚马逊出品的一款基于机器学习的通用代码生成器&#xff0c;可实时提供代码建议。类似 Cursor 和Github AWS CodeWhisperer 亚马逊科技的CodeWhisperer是Amazon于2021年12月推出的一款代码补全工具&#xff0c;与GitHub Copilot类似。主要的功能有:代码补全注释…

网络编程学习

思维导图 代码练习 TCP实现通信 服务器端代码 #include <myhead.h> #define SER_IP "192.168.152.135" #define SER_PORT 8910 int main(int argc, const char *argv[]) {//&#xff11;创建用于监听的套接字int sfd -1;sfd socket(AF_INET,SOCK_STREAM,0)…

python中自定义报错

class MyError(Exception):def __init__(self,num):#录入的数Exception.__init__(self)self.numnumdef __str__(self):return 这是我定义的第%d个异常 %(self.num)使用 try:raise MyError(4) except MyError as e:print(e)raise 其作用是指定抛出的异常名称&#xff0c;以及异常…

【c++】通讯录管理系统

1.系统功能介绍及展示 2.创建项目 3.菜单实现 4.退出功能实现 5.添加联系人—结构体设计 6.添加联系人—功能实现 7.显示联系人 8.删除练习人—检测联系人是否存在 9.删除联系人—功能实现 10.查找联系人 11.修改联系人 12.清空通讯录 #include <iostream> #include <…