【Linux学习笔记】进程概念(中)

news2024/11/24 19:25:01

  • 1. 操作系统的进程状态
  • 2. Linux操作系统的进程状态
  • 3. 僵尸进程
  • 4. 孤儿进程
  • 5. 进程优先级
    • 5.1. 优先级是什么和为什么要有优先级
    • 5.2. Linux中的进程优先级
  • 6. 进程切换
  • 7. 环境变量
    • 7.1. 环境变量的认识
    • 7.2. 环境变量相关的命令
    • 7.3. 环境变量和本地变量
    • 7.4. 命令行参数
    • 7.5. 获取环境变量
    • 7.6. 环境变量学习小总结

1. 操作系统的进程状态

  1. 运行状态

img

程序运行到内存的时候,可以称该程序是一个进程。操作系统为该进程创建了一个PCB,是给CPU管理使用的。进程有很多,而CPU只有一个,所以一旦进程多了,就需要等待。CPU中有一个运行队列,当进程处于运行队列的时候,可以称该进程处于运行状态。

  1. 阻塞状态

img

当进程1想要访问磁盘的时候,磁盘还有其他进程尚未处理完毕,所以让进程1进入磁盘的PCB的等待队列中,此时称进程1的状态为阻塞状态。假设不把进程1放进等待队列中,那么进程1只能处于CPU的运行队列中,就是让CPU等待,这是很不合理的。因为CPU的处理速度很快,而磁盘的处理速度相对于CPU比较慢,不可能等待处理速度慢的磁盘。

例如你电脑的硬件处理速度很烂,比如说是磁盘,那么当你访问磁盘的时候会有卡顿,这个卡顿其实可以理解为所谓的阻塞状态。

  1. 挂起状态

img

如上图所示,这里有4个进程,都是要访问磁盘的,进程1访问磁盘,磁盘尚未处理结束,需要进程1等待,那么此时进程1进入阻塞状态。然后进程2也要访问磁盘,进程3也是,进程4也是,…,那么2、3、4进程都是阻塞状态。此时处于阻塞状态的进程太多了,处于阻塞状态,意味着内存里面都要保存着进程的相关数据,然而此时内存空间不足了,于是操作系统就把其他处于阻塞状态的2、3、4进程的相关数据放到磁盘的某个空间存储,用以减少内存空间的开销。这样的进程的状态称为挂起状态。如下图所示。

img

进程的相关数据被保存了起来,但是进程依然存在于内存,这样减少了内存空间的开销,而进程也因PCB的存在等待被重新唤回。

2. Linux操作系统的进程状态

Linux操作系统的进程状态一般有以下7种状态,下面逐一讲解一下。

img

  1. 运行状态

Linux操作系统进程的运行状态的字母是R。下面用一段代码来查看Linux操作系统下的进程的运行状态。

1 #include <stdio.h>
  2 
  3 int main()
  4 {
  5     while(1);                                                                                                                                                       
  6     return 0;
  7 }

当运行起来的时候,输入查看进程状态(ps axj | head -1 && ps axj | grep “process”)的指令即可看到。

img

  1. 阻塞状态

阻塞状态在Linux操作系统中代表的字母是S。下面用一段代码来查看Linux操作系统下的进程的阻塞状态。

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     int cnt = 0;
  7     while(1)
  8     {
  9         printf("value = %d\n",cnt++);
 10         sleep(1);                                                                                                                                                   
 11     }
 12     return 0;
 13 }

当进程运行的时候,我们观察一下它的进程状态。

img

原因是代码中有printf函数,该函数是向显示器打印,那么也就是说该进程占用显示器资源。而CPU很快,一下子就可以把命令执行完成,但是显示器相对应CPU,处理速度不快,所以该进程的运行时间里,99%都是阻塞状态,1%是运行状态。所以当我们查看进程状态的时候,大概率是阻塞状态。

  1. 暂停状态

暂停状态在Linux操作系统中代表的字母是T。下面用一段代码来查看Linux操作系统下的进程的暂停状态。

1 #include <stdio.h>
  2 
  3 int main()
  4 {
  5     while(1);                                                                                                                                                       
  6     return 0;
  7 }

代码运行起来,进程就是运行状态,此时我们输入相关命令,使得进程的状态变为暂停状态。

img

恢复运行状态:

img

进程重新恢复运行状态。

  • 前台进程与后台进程
#include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     int cnt = 0;
  7     while(1)
  8     {
  9         printf("value = %d\n",cnt++);
 10         sleep(1);                                                                      
 11     }
 12     return 0;
 13 }

以上面这段代码为例,来看一下前台进程与后台进程。

前台进程:

img

像这样不能接受命令的进程,称之为前台进程,只能由crtl + c中止。

后台进程:

当像上面正在运行的进程暂停过后,然后又重新启动,此时进程的状态虽然也是运行状态,但是却与上面进程的运行状态有所不同。

img

  1. 深度睡眠状态

深度睡眠状态在Linux操作系统中代表的字母是D。下面用一段代码来查看Linux操作系统下的进程的深度睡眠状态。

这个状态不好演示,很容易把系统搞崩。所以直接用语言描述。

假如一个进程A,它的任务就是往磁盘里写入大量数据,但是由于磁盘的读取速度比较慢,那么此时进程A就一直占用着资源。后来,越来越多的进程进入内存,导致内存空间的资源吃紧。于是,操作系统开始排查,发现进程A什么都没在干,而是一直占用资源,于是把进程A干掉了。后来进程A被干掉之后,磁盘读取数据任务完成,出来发现进程A不见了,无法交差,但是手头上的数据也不能一直拿着,所以直接扔了。

后来,用户来查看原来要存放在磁盘的数据,发现数据不见了。于是乎,便盘问了操作系统,进程A,磁盘。磁盘说,我只是个干活的,让我干啥就干啥。进程A说,我也是个干活的,突然间有个家伙要把我干了,我也没办法。操作系统说,我的任务就是维护好资源的分配,所以只能把进程A干掉。

用户觉得谁也没有错,于是制定相关的规定。给予某个重要的进程一个免死金牌,例如进程A,当资源吃紧的时候,操作系统不能杀死带有免死金牌的进程。那么此时,这个带有免死金牌的进程就会进入深度睡眠状态,此时这个进程不能被杀死,只能等进程本身自己醒来或者物理断电解决进程。

一句话总结,处于深度睡眠状态的进程,操作系统是杀不掉的,只能等进程自己醒来或者物理断电。

  1. 追踪暂停状态

追踪暂停状态在Linux操作系统中代表的字母是t。下面用一段代码来查看Linux操作系统下的进程的追踪暂停状态。

 1 #include <stdio.h>
  2 
  3 int main()
  4 {
  5     printf("hello world\n");
  6     printf("hello world\n");
  7     printf("hello world\n");
  8     printf("hello world\n");
  9     printf("hello world\n");
 10     printf("hello world\n");
 11     printf("hello world\n");
 12     printf("hello world\n");
 13     printf("hello world\n");
 14     printf("hello world\n");                                                           
 15     return 0;
 16 }

当我将这段代码运行起来并调试的时候,就可以清楚地看到这个追踪暂停状态。

img

3. 僵尸进程

  1. 僵尸状态

将状态在Linux操作系统中代表的字母是Z。用一个例子,浅浅的认识一下僵尸状态。

一天,小明在路上看到有一个人躺在地上噶了,此时小明选择了报警。警察来了之后,封锁了现场,并且叫来了法医进行验尸。此时,尸体会有一段时间用来被检验,并等待结果,最终宣告死亡。

切换到进程的角度,一个进程退出了,其中资源并不会马上被回收,而是保留一段时间,等待父进程或者操作系统读取。其中这段等待被回收的状态,可以称该进程的状态是僵尸状态。或者可以说该进程没有被父进程或者操作系统回收,也可称该进程是僵尸进程。

如何创建僵尸进程呢?那就是确保父进程正常运行,子进程直接退出。

来看代码:

                                                                                                                                                                                    ⮂⮂ buffers 
  1 #include <stdio.h>  
  2 #include <unistd.h>  
  3 #include <stdlib.h>  
  4 int main()  
  5 {  
  6     pid_t id = fork();  
  7     if(id == 0)  
  8     {  
  9          //child
 10          printf("i am a child process,process id is :%d,parent id is :%d\n",getpid(),getppid());
 11          sleep(3);
 12          exit(1);                                                                                                                                                                                               
 13     }                  
 14     else              
 15     {     
 16         //parent
 17         while(1)  
 18         {         
 19              printf("i am a parent process,process id is :%d,parent id is :%d\n",getpid(),getppid());
 20              sleep(1);                                                                                 
 21         }                                                                                              
 22     }                                                                                                
 23     return 0;         
 24 }      

img

僵尸进程是无法被杀死的,因为它已经退出了,已经退出了的进程是杀不死的。但是它的pcb还存着,等待父进程读取,然后回收。如果父进程不回收,那么就会导致内存泄漏。

4. 孤儿进程

孤儿进程顾名思义就是父进程死了,但是子进程还在跑。这样的进程称为孤儿进程。

下面来看一段代码,看看是如何生成孤儿进程的。

#include <stdio.h>    
#include <unistd.h>    
#include <stdlib.h>    
int main()    
{    
    pid_t id = fork();    
    if(id == 0)    
    {    
         //child    
         while(1)    
         {    
             printf("i am a child process,process id is :%d,parent id is :%d\n",getpid(),getppid());    
             sleep(1);                                                                                                                                                                                              
         }    
    }    
    else    
    {    
        //parent    
        while(1)    
        {    
             printf("i am a parent process,process id is :%d,parent id is :%d\n",getpid(),getppid());    
             sleep(1);    
        }    
    }    
    return 0;    
}

img

如果操作系统不领养该进程,该进程退出的时候,变成了僵尸,将会没有人给它收尸。而操作系统作为一个管理角色,必须对其进行处理。

用一句话总结,被领养的进程,我们可以称该进程是孤儿进程。

如果是前台进程创建的子进程,那么该子进程变为孤儿进程后,将会变成后台进程,此时只能用kill命令杀掉该进程。

5. 进程优先级

5.1. 优先级是什么和为什么要有优先级

  1. 优先级的概念

优先级其实就是排队的先后,优先级在生活中很常见,例如食堂排队打饭,面试工作时懂XX技术优先,这些都是常见的优先级。

  1. 为什么要有优先级

那么为什么要有优先级呢?是因为资源是有限的,例如饭堂打饭,饭如果打完了,那么优先级低的人就吃不到饭;例如面试时懂XX技术的优先级高,那么有可能优先级低的人就无法获取这份工作…

5.2. Linux中的进程优先级

在Linux中,进程的优先级本质就是PCB上的一个数字。就好比你生活中去一家餐厅吃饭,因为位置不多,所以需要排队,如果你愿意等下去,服务员就会给你一个排队的号码,这个号码就是你的优先级。

下面创建一个进程,并输入相关的指令(ps - la)查看进程优先级。

  1. 最终进程优先级 = 老的优先级(固定80) + nice值

img

  1. 可以用top工具更改进程的优先级,主要是通过更改nice值

img

img

img

img

注意nice值的范围是[-20,19],所以最小是-20,最大是19。所以进程的最终优先级的范围是[80-20, 80+19]

6. 进程切换

假设你的电脑只有1个CPU,那么就会有很多进程占用CPU的资源。但是当用起来的时候,就感觉进程都是一起运行的。例如你可以同时打开qq,微信,同时在qq和微信上发消息。这是因为操作系统采用进程切换的方法,让多进程在宏观上运行的时候像是一起运行的,实际在微观上是串行的。

具体点就是操作系统会给多个进程分配时间片,当某个进程的时间片用完了,那么该进程就是被操作系统拿下,切换另一个进程运行。这个时间是很短很短的,所以我们一般感觉不出来。

对时间片的概念,可以举这么一个例子:A要考研,他不可能说先把数学学完了再去学英语,然后再去学专业课。一般考研的都是,今天给数学分配多少时间,给英语分配多少时间,给专业课分配多少时间。在这个分配好的时间片里,无论你数学完成的怎么样,我数学的时间片到了,我就得切换到英语科目去学习。最后到考研结束,那么数学也能学完,英语也能学完,专业课也能学完。

img

把学习数学想象成是一个进程1,学习英语是进程2,学习专业课是进程3,小A是一个CPU,这就可以类比到计算机的进程切换的概念中去。

那么进程的切换是怎么完成的?下面来浅浅地认识一下。

  1. 先来看一个例子

A是一名大学生,他突然有一天想去服兵役,然后就报名参加了当兵。报名后,A向学校说明了他的情况,学校学籍处给他保留了相应的学籍。当A两年义务兵结束后,选择继续回归校园。此时,退伍回来后,A就向学校学籍处拿回自己的学籍,然后就重新恢复了自己大学生的身份。img

切换到计算机的世界。A是一个进程,当A进程去使用打印机资源的时候,那么CPU中的相关的寄存器就会给进程A保留了相关的数据。当进程A完成了打印的任务,回到了原来的轨道。此时,进程A回来后,A就会拿到原来寄存器里的相关数据,继续运行自己的进程。

img

7. 环境变量

7.1. 环境变量的认识

环境变量其实可以认为是一个字符串,常见的环境变量有PATH,HOME,SHELL…,每个环境变量都是为了应付不同的应用场景的。

  1. PATH

当我们在命令行输入各种指令的时候,是否有想过为什么直接输入就可以执行相应的操作呢?而当我们写好了一个代码,运行的时候却要在可执行程序的前面指定好路径呢?

其实命令行的指令也是指定好了路径的,这个行为是环境变量帮我们完成的。

img

如果想要我们自己写的代码也能不加路径直接运行,也有方法。

  • 将test拷贝到/usr/bin/img
  • 配置环境变量

img

当我们在命令行输入相关的指令,bash进程都会去PATH底下逐一查找,查看这些目录下有没有该命令,如果有则运行,没有则提示找不到。

img

那么我们只需要把我们代码的路径添加到PATH中,那么运行的时候我们就不用加路径了。

img

img

环境变量可以帮助我们在运行相应的指令的时候,让指令识别路径,身份认证等操作。

例如:

#include <stdio.h>    
#include <string.h>    
#include <stdlib.h>    
int main()    
{    
	//获取当前user的环境变量
    char* name = getenv("USER");    
    if(strcmp(name,"root") == 0)    
    {    
        printf("%s = %s\n",name,"root");    
    }    
    else    
    {    
        printf("%s = %s\n",name,name);                                                                                                                                                         
    }    
    return 0;    
} 

当我是用户1的身份运行时:

img

当我是root身份运行时:

img

所以环境变量的用途有很多,它不仅可以帮我们识别路径,也可以帮我们识别用户身份等等…

用背单词的例子来理解环境变量。

img

img

7.2. 环境变量相关的命令

  1. echo命令

操作:显示某个环境变量

示范:

img

  1. env

操作:显示所有的环境变量

示范:

img

  1. set命令

操作:显示本地变量

示范:

img

  1. export命令

操作:设置一个新的环境变量

示范:

img

  1. unset命令

操作:清除某个环境变量

示范:

img

7.3. 环境变量和本地变量

环境变量具有全局性,无论你在哪里用都可以。而本地变量只能当前进程用。

用背单词的例子来认识:

img

img

是因为子进程继承了父进程的时候,顺便继承了环境变量,所以才说环境变量具有全局性。

7.4. 命令行参数

C语言中的main函数是可以带有参数的,例如:

int main(int argc, char* argv[])
{
	return 0;
}

那么带了参数又有什么用呢?

 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 int main(int argc, char* argv[])
  5 {
  6     for(int i = 0; i < argc; i++)
  7     {
  8         printf("argv[%d]--->%s\n",i,argv[i]);                                                                                                                       
  9     }
 10     return 0;
 11 }

运行结果:

img

img

所以我们之前学习的命令,为什么带上选项可以有不同的功能,就是因为命令行参数的存在。

#include <stdio.h>    
#include <string.h>    
#include <stdlib.h>    
int main(int argc, char* argv[])    
{    
    if(argc != 2)    
    {    
        printf("Usage: \n\t%s [-a/-b/-c/-ab/-bc/-ac/-abc]\n", argv[0]);    
        return 1;                                                                                                                                                                              
    }    
    if(strcmp("-a", argv[1]) == 0)    
    {    
        printf("功能a\n");    
    }    
    if(strcmp("-b", argv[1]) == 0)    
    {    
        printf("功能b\n");    
    }    
    if(strcmp("-c", argv[1]) == 0)    
    {    
        printf("功能c\n");    
    }    
    if(strcmp("-ab", argv[1]) == 0)    
    {    
        printf("功能ab\n");    
    }    
    if(strcmp("-bc", argv[1]) == 0)    
    {    
       printf("功能bc\n");    
    }    
    return 0;
}

运行结果:

img

可以简单的认为在命令行上执行的程序的程序名,就是argv[0],后面带上的选项就是argv[i]。

7.5. 获取环境变量

  1. 系统接口getenv()

这里就是简单的系统调用,就不再展示了,上面的有一段代码是写过的。

  1. char* env[]

main函数中可以有三个参数,其中第三个参数就是环境变量,它同char* argv[] 一样都是一个指针数组,数组的元素都是char类型的,最后一个char是NULL,因此我们可以将它打印出来。

 #include <stdio.h>
    2 #include <string.h>
    3 #include <stdlib.h>
    4 int main(int argc, char* argv[], char* env[])
    5 {
    6     for(int i = 0; env[i]; i++)
    7     {
    8         printf("env[%d]---->%s\n",i,env[i]);                                                                                                                      
    9     }
   10     return 0;
   11 }

运行结果:

img

  1. extern char* environ

在Linux中,提供一个二级指针,指向了一个保存环境变量的char*[],因此我们只需要在代码中声明该变量,也可以打印出所有的环境变量。

#include <stdio.h>    
#include <string.h>    
#include <unistd.h>    
#include <stdlib.h>    
int main()                                                                                                                                                              
{    
    extern char** environ;    
    for(int i = 0; environ[i]; i++)    
    {    
        printf("env[%d]---->%s\n",i,environ[i]);    
    }    
    return 0;    
} 

运行结果:

img

7.6. 环境变量学习小总结

  1. 什么是环境变量?

环境变量简单的来说就是字符串,它可以帮助用户识别路径,识别用户的身份等等操作。

环境变量具有全局性,本地变量具有局部性。具体可以参看背单词的例子。

  1. 命令行参数

当我们在命令行输入指令的时候,操作系统和shell是怎么认识的?就是通过main函数的参数来识别的。其中我们输入的命令行会被操作系统和shell放到一个char* 数组里面,用来解析我们的各种命令。

  1. 如何获取环境变量

参考3.5所讲的内容。

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

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

相关文章

突破防火墙的一种方法

当Linux防火墙阻止来自某个ip的数据时&#xff0c;它应该是根据ip数据报里“源IP地址”字段取得的对方ip吧&#xff0c;那对方就不能通过篡改“源IP地址”来绕过防火墙吗&#xff1f;NAT模式下的路由器就修改了这个字段。 但这样的话&#xff0c;攻击者是收不到服务器返回的数…

通过内网穿透分享本地电脑上有趣的照片:部署piwigo网页

通过cpolar分享本地电脑上有趣的照片&#xff1a;部署piwigo网页 文章目录 通过cpolar分享本地电脑上有趣的照片&#xff1a;部署piwigo网页前言1.Piwigo2. 使用phpstudy网页运行3. 创建网站4. 开始安装Piwogo5. 设定一条内网穿透数据隧道6. 与piwigo网站绑定7. 在创建隧道界面…

k8s 多网卡方案multus

kubernetes 多网卡方案之 Multus_CNI 部署以及基本使用 一、multus cni 出现的背景 在k8s的环境中启动一个容器&#xff0c;默认情况下只存在两个虚拟网络接口&#xff08;loopback 和 eth0&#xff09;&#xff0c; loopback 的流量始终都会在本容器内或本机循环&#xff0c…

CSAPP BOMB LAB part2

bomb lab part2 phase3 汇编语法 switch 汇编版本 switch 例子: switch 使用 jump table movl 指令 cmpl指令是x86汇编语言中的一个比较指令&#xff0c;用于比较两个操作数的值。cmpl指令的格式如下&#xff1a; cmpl source, destinationsource和destination可以是…

为什么我电脑上C:\Windows\System32\config\regback文件夹是空的,怎么设置才能有备份文件

环境&#xff1a; Win10 专业版 19041 问题描述&#xff1a; 为什么我电脑上C:\Windows\System32\config\regback文件夹是空的&#xff0c;怎么设置才能有备份文件 解决方案&#xff1a; 微软说从 Windows 10 版本 1803 开始&#xff0c;系统注册表不再备份到 RegBack 文件…

第二章 线性表【数据结构与算法】【精致版】

第二章 线性表【数据结构与算法】【精致版】 前言版权第二章 线性表2.1 应用实例应用实例一 约瑟夫环问题(Josephus problem)应用实例二 一元多项式运算器 2.2 线性表的概念及运算2.2.1线性表的逻辑结构2.2.2 线性表的运算 2.3 线性表的顺序存储2.3.1 顺序表2.3.2 顺序表的基本…

网络安全进阶学习第二十一课——XXE

文章目录 一、XXE简介二、XXE原理三、XXE危害四、XXE如何寻找五、XXE限制条件六、XXE分类七、XXE利用1、读取任意文件1.1、有回显1.2、没有回显 2、命令执行&#xff08;情况相对较少见&#xff09;3、内网探测/SSRF4、拒绝服务攻击(DDoS)4.1、内部实体4.2、参数实体 八、绕过基…

制造企业如何三步实现进销存管理?

制造企业如何三步实现进销存管理&#xff1f; 一、什么是进销存软件&#xff1f; 进销存软件是一种针对制造业企业设计的管理软件系统&#xff0c;旨在协调和优化企业的生产、采购、销售以及库存管理等方面的活动。该系统的主要目标是提高企业的生产效率、降低库存成本、优化…

C++二分查找算法的应用:俄罗斯套娃信封问题

本文涉及的基础知识点 二分查找 题目 给你一个二维整数数组 envelopes &#xff0c;其中 envelopes[i] [wi, hi] &#xff0c;表示第 i 个信封的宽度和高度。 当另一个信封的宽度和高度都比这个信封大的时候&#xff0c;这个信封就可以放进另一个信封里&#xff0c;如同俄罗…

npm ERR! code ELIFECYCLE

问题&#xff1a; 一个老项目&#xff0c;现在想运行下&#xff0c;打不开了 npm install 也出错 尝试1 、使用cnpm npm install -g cnpm --registryhttps://registry.npm.taobao.org cnpm install 还是不行 尝试2、 package.json 文件&#xff0c;去掉 那个插件 chorm…

VS Code 开发 Spring Boot 类型的项目

在VS Code中开发Spring Boot的项目&#xff0c; 可以导入如下的扩展&#xff1a; Spring Boot ToolsSpring InitializrSpring Boot Dashboard 比较建议的方式是安装Spring Boot Extension Pack&#xff0c; 这里面就包含了上面的扩展。 安装方式就是在扩展查找 “Spring Boot…

​​​​​​​2022年上半年 软件设计师 上午试卷(33-68)

35 C 36 D 该题在2013年下半年考过类似的题目&#xff0c;从图中可见&#xff0c;页内地址的长度为12位&#xff0c;2124096&#xff0c;即4K&#xff0c;页号长度为21-12110&#xff0c;2101024&#xff0c;段号长度为31-22110&#xff0c;2101024。故正确答案为D。 37&#x…

传感器类总结(一)MPU9250 1原理介绍

1简介 MPU9250是一款9轴运动跟踪装置&#xff0c;在它3x3x1mm的封装中集成了3轴陀螺仪&#xff0c;3轴加速度计&#xff0c;3轴磁力计以及运动处理器&#xff08;DMP&#xff09;并且兼容 MPU6515。通过IIC&#xff0c;可以直接输出9轴的全部数据。因此它也是四轴姿态结算的基…

【LeetCode刷题-链表】--203.移除链表元素

203.移除链表元素 方法&#xff1a;定义一个节点指向头节点head&#xff0c;避免头结点单独操作 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* …

哪个牌子的骨传导蓝牙耳机好?盘点市面上口碑最好的五款骨传导耳机

随着技术的发展&#xff0c;运动蓝牙耳机这个类别已经进化到了骨传导的形式&#xff0c;也受到了广大运动爱好者的一致好评&#xff0c;在日常运动中&#xff0c;也经常会看到佩戴骨传导耳机的消费者&#xff0c;但普通的骨传导耳机却表现并不是很好&#xff0c;所以在选购骨传…

修改Typora默认微软雅黑字体

修改Typora字体 写在前面 我最近在折腾windows电脑&#xff0c;从macos转像windows不容易啊&#xff0c;因为键盘快捷键经常弄错&#xff0c;这篇文章就是修改Typora中字体显示的问题。 正文内容 我发现在windows中&#xff0c;字体非常的难看&#xff0c;微软雅黑也太丑了…

Zeebe 微服务编排引擎 入门

相关阅读: linux 安装 zeebe: Zeebe学习(一)——Linux下安装zeebe以及快速入门_互联网集市 Zeebe是一个用于微服务编排的工作流引擎。 这篇文章将帮助你确切地了解什么是Zeebe以及它如何可能与你相关。我们将简要介绍Zeebe以及它所解决的问题,然后再进行更详细的介绍。…

求解一个整数中含多少个1

1.问题描述&#xff1a;给定一个整数&#xff0c;统计其对应的二进制中含有1的个数。比如8(0000 1000),对应的二进制数中&#xff0c;只含有一个1. 2.设计思路&#xff1a;对x取余&#xff1a;zx%2。如果z&#xff01;0&#xff0c;说明x的末尾不是为1.对于一个二进制x4x3x2x1…

JAVA虚拟机-第2章 Java自动内存管理-内存区域与内存溢出异常以及对象在Java堆中如何被new、管理和访问(1)

在java中&#xff0c;在虚拟机自动内存管理机制的帮助下&#xff0c;不再需要为每一个new操作去写配对的delete/free代码&#xff0c;不容易出现内存泄漏和内存溢出问题。但正是因为Java程序员把控制内存的权力交给了Java虚拟机&#xff0c;一旦出现内存泄漏和溢出方面的问题&a…

pikache靶场通关——XXE

文章目录 前言一、有返回显示XXE1、在输入框输入随机数据&#xff0c;抓包2、在BP数据包和靶场中各尝试使用正确的XML格式重新输入3、使用BP进行URL编码&#xff0c;利用XXE来读取系统文件 二、无回显XXE1、模拟使用的机器2、修改代码实现靶场无回显2.1、修改靶场代码&#xff…