当前位置: 首页 > news >正文

【通用】操作系统 知识总结:IPC方式 / 进程线程 / 死锁 / 虚拟内存 / 段页存储

常见问题:

  1. 跨进程通信方式(IPC)有哪些?其底层原理及其对应应用场景分别是什么?
  2. 进程与线程的定义、特点及其区别是什么?
  3. 死锁的必要条件是什么?该如何处理?
  4. 虚拟内存的定义及其特点。
  5. 虚拟地址、逻辑地址、线性地址、物理地址的区别。
  6. 段存储、页存储、段页存储的定义及其区别。

1 跨进程通信方式(IPC)有哪些?其底层原理及其对应应用场景分别是什么?

1 共享内存

多个进程通过读/写 同1个共享文件来交换数据

进程间是独立的,若需要共享空间,需要通过特殊的系统调用

原理

  • 内存映射,即通过把1个共享文件映射到自己的进程地址空间,实现进程间通信
  • 1个文件可以同时被多个进程操作,其他进程也可以通过相同的文件进行映射

在 Android 中的应用场景

  1. 高性能数据传输:
  • 当需要在不同进程之间快速传输大量数据时,共享内存可以提供比传统的进程间通信方式(如 Binder、Socket 等)更高的性能。
  • 例如,在视频处理、图像渲染等需要大量数据交换的应用中,可以使用共享内存来提高数据传输的效率。
  1. 跨进程资源共享:
  • 多个进程可以共享同一块内存区域,从而实现资源的共享。例如,多个进程可以共享一个数据库缓存、一个图像缓冲区等。
  • 这可以减少资源的重复分配和释放,提高系统的性能和资源利用率。

实现方法

  1. 使用 Android NDK:
  • Android NDK(Native Development Kit)提供了一些接口来创建和管理共享内存。可以使用 C/C++ 代码来实现共享内存的创建、映射和访问。
  • 例如,可以使用mmap函数来将一个文件或一块匿名内存映射到进程的地址空间。然后,其他进程可以通过相同的文件或内存区域进行映射,从而实现共享访问。
  1. 使用 Java 层的接口:
  • 虽然 Java 本身没有直接提供共享内存的接口,但可以通过 JNI(Java Native Interface)调用 C/C++ 代码来实现共享内存的功能。
  • 另外,也可以使用一些第三方库或框架来实现共享内存的功能。例如,Android 的 Parcelable 接口可以用于在不同进程之间传递复杂的数据结构,但它实际上是通过序列化和反序列化来实现的,性能可能不如共享内存。

2 Bundle

消息传递

  • 进程简单数据交换 是以格式化的消息为单位的;
  • 通过系统提供的发生消息 & 接收消息 2个原语进行通信

Bundle的底层原理是:实现了序列化接口Parcelable

在Bundle中添加需要传输的数据 & 通过IntentService发送出去

基本用法

// 创建 Bundle 对象:Bundle bundle = new Bundle();// 放入基本数据类型:bundle.putInt("key_int", 10);bundle.putString("key_string", "Hello");bundle.putBoolean("key_boolean", true);
// 放入自定义对象(需实现 Serializable 或 Parcelable 接口):MyObject myObject = new MyObject();bundle.putSerializable("key_object", myObject);
// 从 Bundle 中取出数据:int valueInt = bundle.getInt("key_int", 0);String valueString = bundle.getString("key_string", null);boolean valueBoolean = bundle.getBoolean("key_boolean", false);
// 取出自定义对象:MyObject myObject = (MyObject) bundle.getSerializable("key_object");

实际应用

  1. Activity 之间传递数据:
    当启动一个新的 Activity 时,可以通过 Intent 携带 Bundle 来传递数据。
 Intent intent = new Intent(this, SecondActivity.class);Bundle bundle = new Bundle();bundle.putString("data_key", "Data to pass");intent.putExtras(bundle);startActivity(intent);

在接收数据的 Activity 中获取数据:

     Bundle extras = getIntent().getExtras();if (extras!= null) {String data = extras.getString("data_key");}
  1. Fragment 之间传递数据:
    与Activity之间传递数据类似

  2. 保存和恢复状态:
    在 Activity 或 Fragment 的生命周期方法中,可以使用 Bundle 来保存和恢复状态。
    例如,在onSaveInstanceState()方法中保存数据:

     @Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putString("saved_data_key", "Data to save");}

在onCreate()或onViewStateRestored()方法中恢复数据:

     @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (savedInstanceState!= null) {String savedData = savedInstanceState.getString("saved_data_key");}}

3 信使 Messenger

本质

同2,也属于消息传递

基于Binder机制实现的跨进程通信

基本用法

  • 在Messenger中放入需要传递的数据 即可传递
  • 应用场景:服务端串行处理客户端消息
  1. 创建 Messenger:
    在服务端(Service)创建一个Messenger对象,并将其与一个Handler关联,用于处理接收到的消息。
        public class MyService extends Service {private final Messenger messenger = new Messenger(new IncomingHandler());private static class IncomingHandler extends Handler {@Overridepublic void handleMessage(Message msg) {// 处理来自客户端的消息switch (msg.what) {case MSG_FROM_CLIENT:// 执行相应操作break;default:super.handleMessage(msg);}}}@Overridepublic IBinder onBind(Intent intent) {return messenger.getBinder();}}
  1. 在客户端(Activity 等)获取 Messenger:
    通过绑定服务获取服务端返回的IBinder,然后创建一个Messenger对象指向服务端的Messenger。
        public class MyActivity extends Activity {Messenger serviceMessenger;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Intent intent = new Intent();intent.setComponent(new ComponentName("com.example.otherprocess", "com.example.otherprocess.MyService"));bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);}private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {serviceMessenger = new Messenger(service);// 发送消息给服务端Message msg = Message.obtain(null, MSG_FROM_CLIENT);try {serviceMessenger.send(msg);} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName className) {serviceMessenger = null;}};}

Messenger 特点

  1. 简单易用:
    Messenger的使用相对简单,不需要处理复杂的 AIDL(Android Interface Definition Language)接口定义和跨进程异常处理。
  2. 单向通信:
    它通常用于单向通信,即客户端向服务端发送消息,服务端处理消息后不需要直接回复客户端。如果需要双向通信,可以结合多个Messenger对象或者使用其他更复杂的 IPC 机制。
  3. 安全可靠:
    Android 系统会处理消息的传递和接收,确保通信的安全性和可靠性。同时,Messenger基于Handler机制,消息的处理在服务端的主线程中进行,避免了多线程同步的问题。

4 AIDL Android接口定义语言

底层基于Binder

通过将Binder对象转换成AIDL接口类型 & 调用其内方法,实现跨进程通信

应用场景

1对多的并发跨进程通信

具体应用

一、创建 AIDL 文件

在 Android Studio 中,在app/src/main/aidl目录下创建一个 AIDL 文件,比如IMyService.aidl:

   package com.example.myapp;interface IMyService {String getMessage();}

二、实现服务端

  1. 创建一个服务类,实现 AIDL 接口定义的方法:
   public class MyService extends Service {private final IMyService.Stub binder = new IMyService.Stub() {@Overridepublic String getMessage() {return "Hello from service";}};@Nullable@Overridepublic IBinder onBind(Intent intent) {return binder;}}
  1. 在AndroidManifest.xml中注册服务:
   <service android:name=".MyService"><intent-filter><action android:name="com.example.myapp.IMyService" /></intent-filter></service>

三、实现客户端

绑定服务并获取 AIDL 接口的实例:

   public class MainActivity extends AppCompatActivity {private IMyService myService;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent();intent.setComponent(new ComponentName("com.example.myapp", "com.example.myapp.MyService"));bindService(intent, connection, Context.BIND_AUTO_CREATE);}private ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {myService = IMyService.Stub.asInterface(service);try {String message = myService.getMessage();Log.d("MainActivity", message);} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName className) {myService = null;}};}

在这个示例中,服务端实现了一个 AIDL 接口定义的方法,并在客户端绑定服务后获取了服务端的 AIDL 接口实例,从而可以调用服务端的方法实现跨进程通信。

5 ContentProvider

四大组件之一

底层基于Binder

Android中专门用于跨进程通信

6 套接字 Socket

底层原理是:TCP/IP协议族

应用层 与 TCP/IP协议族通信的中间软件抽象层,表现为一个编程接口

使用类型主要有两种:

  1. 流套接字:基于TCP协议,采用字节流的方式传输数据
  2. 数据报套接字:基于UDP协议,采用数据报文方式传输数据

2. 进程与线程的定义、特点及其区别是什么?

2.1 进程

  • 定义
    是进程实体的运行过程 & 系统进行资源分配和调度的一个独立单位

  • 作用
    使多个程序可 并发执行,以提高系统的资源利用率和吞吐量

  • 进程状态说明(前三个为基础状态)
    在这里插入图片描述

进程顺利运行需要的资源:2类:

  1. 某资源/某事件
  2. 处理机(CPU时间片)
  3. 只缺前者 阻塞,只缺后者 就绪,二者兼备则 运行
  • 状态转换
    在这里插入图片描述

2.2 线程

  • 定义
    一个基本的CPU执行单元 & 程序执行流的最小单元
  1. 比进程更小的可独立运行的基本单位,可理解为:轻量级进程
  2. 组成:线程ID + 程序计数器 + 寄存器集合 + 堆栈
  3. 注:线程自己不拥有系统资源,与其他线程共享进程所拥有的全部资源。 作用

减少程序在并发执行时所付出的时空开销,提高操作系统的并发性能。

状态说明
拥有类似于进程的就绪、阻塞、运行3种基本状态,具体如下图:
在这里插入图片描述

2.3 区别

在这里插入图片描述

3. 死锁的必要条件是什么?该如何处理?

3.1 定义

运行过程中,多个进程因争夺资源而造成的一种互相等待的僵局

若无外力作用,这些进程都将无法向前推进

3.2 原因

  1. 竞争资源:请求同一有限资源的进程数 > 可用资源数
  2. 进程推进顺序非法:请求 & 释放资源顺序不合理,如资源等待链

3.3 死锁的必要条件

1. 互斥条件

  • 一段时间内资源仅为一个进程占有,即 排他
  • 此时若有其他进程请求该资源,则请求进程只能等待

2. 不可剥夺

  • 进程已经获得的资源在未使用完毕前,不能被其他进程强行夺走
  • 只能由获得资源的进程自己主动释放

3. 请求&保持

  • 请求 已被其他进程占有的资源时,该请求会被阻塞,但自身的资源保持不释放

4. 循环等待

  • 存在一种 进程资源的循环等待链,链中每一个进程已获得资源的同时 被链中下个进程所请求

3.4 处理策略

在这里插入图片描述

3.5 其他办法:银行家算法

最著名的死锁避免算法

  1. 当进程首次申请资源时,要测试该进程对资源的最大需求量
  2. 若系统现存的资源可满足它的最大需求量,则按当前的申请量分配资源;否则,推迟分配

4. 虚拟内存的定义及其特点

4.1 定义

一个通过对内、外存调度、只是从逻辑上扩充了内存、但实际不存在的内存存储器

4.2 原理

  1. 部分装入:基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其他部分留在外存,就可以启动程序执行
  2. 请求调入:在程序执行时,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存 & 继续执行程序
  3. 置换功能:操作系统将内存中暂时不使用的内容换出到外存上,从而腾出空间存放将要调入内存的信息

4.3 特性

  1. 多次性:一个作业可分多次被调入内存
  2. 对换性:作业运行过程中存在换进换出的过程,即 换出暂时不用的数据,换入需要的数据
  3. 虚拟性:从逻辑上扩充了内存的容量

4.4 实现方式

  1. 请求分页存储管理
  2. 请求分段存储管理
  3. 请求段页式存储管理

4.5 大小

  1. 由计算机的地址结构决定
  2. 并非是内存和外存的简单相加

5. 虚拟地址、逻辑地址、线性地址、物理地址的区别

  • 虚拟地址:虚拟内存中的地址
  • 逻辑地址:由程序产生的与段相关的偏移地址部分。如C语言中 &取值操作 所得的地址
  • 物理地址:出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。
    a. 若启用分页机制,线性地址会使用页目录 & 页表中的项变换成物理地址
    b. 若无启用分页机制,线性地址就是物理地址
  • 线性地址:逻辑地址到物理地址变换之间的中间层

6. 段存储、页存储、段页存储的定义及其区别

6.1 页存储

6.1.1 储备知识

  1. 内存页
    用户程序的逻辑地址空间 被划分成的若干个固定大小的区域

  2. 块的定义
    内存物理空间也分成相对应的若干个物理块,与页大小相等
    即 从主内存空间被划分出来的内存块

注:

  • 块 是主存的基本单位
  • 每个进程以块为单位进行划分 & 以块为单位逐个申请主存中的块空间

6.1.2 定义

将用户程序的任一页放在内存的任一块中,实现了离散分配 & 页的存储

6.1.3 特点

优点:无外碎片 & 每个内碎片不超过页的大小
缺点:程序需全部装入内存 & 要求有相应的硬件支持

6.1.4 地址结构

分页存储管理的逻辑地址结构:
在这里插入图片描述

6.1.5 页表

  1. 因数据存储在不同的页面中,而页面又离散的分布在内存中的不同中
  2. 为了便于在内存中找到进程的每个页面所对应的物理块,系统为每个进程建立一张页表,记录页面在内存中对应的物理块号,即 逻辑地址 & 实际存储地址之间的映射关系,以实现从页号到物理块号的映射

页表一般存放在内存中

在这里插入图片描述

6.2 段存储

6.2.1 定义

将用户程序地址空间分成若干个大小不等的段,每段可以定义一组相对完整的逻辑信息。存储分配时,以段为单位,段与段在内存中可以不相邻接,也实现了离散分配

6.2.2 特点

  1. 优:可编写 & 编译、可针对不同类型的段采用不同的保护、可按段为单位共享(含 通过动态链接进行代码共享)
  2. 缺:会产生碎片

6.3 段页存储

6.3.1 定义

段式管理 & 页式管理方案结合而成的方案

  1. 作业的地址空间首先被分成若干个逻辑分段,每段都有自己的段号
  2. 再将每段分成若干个大小相等的页

对于主存空间也分成大小相等的页,主存的分配以页为单位。

6.3.2 特点

  1. 优:具有段式管理 & 页式管理方案的优点
  2. 缺:由于管理软件的增加,复杂性和开销也就随之增加

http://www.mrgr.cn/news/78502.html

相关文章:

  • Unity中的数学应用 之 角色移动中单位化向量的妙用 (小学难度)
  • 第02章 使用VMware部署CENTOS系统
  • 51-基于单片机的智能语音识别与处理系统设计
  • 互联网视频推拉流EasyDSS视频直播点播平台视频转码有哪些技术特点和应用?
  • Python的排序算法
  • 【技术支持】vscode不使用插件,两种方式重命名html标签对
  • Oracle对比表与表之间的结构
  • 20241128解决Ubuntu20.04安装libwxgtk3.0-dev异常的问题
  • linux内核面试题精选及参考答案
  • 探讨播客的生态系统
  • 零基础快速掌握——C语言基础【数据类型】【运算符】
  • python array矩阵相关操作
  • 《操作系统 - 清华大学》6 -1:局部页面置换算法:最优页面置换算法
  • 针对Qwen-Agent框架的Function Call及ReAct的源码阅读与解析:Agent基类篇
  • Robot Framework框架中常用的变量
  • A052-基于SpringBoot的酒店管理系统
  • Flink 离线计算
  • ais_server 学习笔记
  • mongodb文档字符串批量替换
  • JAVA项目-------医院挂号系统
  • vue3 tinymce7版本 完美适配基本需求(特殊需求外)
  • 【JavaEE初阶 — 网络编程】TCP流套接字编程
  • 《Learn Three.js》学习(2)构建Three.js基本组件
  • nginx安装和负载均衡
  • JVM_总结详解
  • A050-基于spring boot物流管理系统设计与实现