草庐IT

操作系统6道面试题

越山 阅书 悦己 2023-03-28 原文

20230321

1.进程和线程的区别

进程(Process)和线程(Thread)是操作系统中的两个重要概念。

一个进程可以看作是一个正在运行的程序实例,它拥有自己的地址空间、内存、数据栈和其他系统资源。一个进程可以包含多个线程,每个线程都是进程中独立的执行流,每个线程共享进程的地址空间和系统资源。

线程是进程中的一个执行单元,它是操作系统调度的最小单位,不同的线程可以并行执行,从而提高了程序的并发性和效率。线程比进程更轻量级,创建和销毁的开销更小,也更容易实现线程间的通信和同步。

因此,进程和线程的主要区别如下:

  • 资源占用:进程是资源分配的最小单位,而线程是CPU调度的最小单位。每个进程都有自己的地址空间和系统资源,而多个线程共享进程的资源。

  • 通信和同步:不同进程之间通信和同步的成本比较高,而线程之间可以通过共享进程的内存空间实现通信和同步,成本更低。

  • 切换开销:由于每个进程都拥有自己的地址空间和系统资源,因此进程间的切换开销比线程更大。

  • 安全性:由于每个进程都拥有自己的地址空间和系统资源,因此进程间的安全性比线程更高。如果一个线程崩溃,会影响整个进程的稳定性,而一个进程崩溃只会影响自己。

总的来说,进程和线程都是并发编程中重要的概念,它们各有优缺点,需要根据具体的场景选择使用。

2.描述系统调用的整个流程

系统调用是操作系统提供给应用程序使用的接口,它允许应用程序通过操作系统内核来访问底层资源和功能。下面是系统调用的一般流程:

应用程序执行系统调用指令。这个指令将控制权转移到操作系统内核。

操作系统内核处理系统调用。这包括验证参数、权限检查、资源分配等操作,确保应用程序请求的操作是安全和合法的。

操作系统内核执行请求的操作。这可能涉及到与硬件交互,或者对某些内核数据结构进行操作,如文件描述符、进程控制块等。

操作系统内核将结果返回给应用程序。这个过程可能涉及到复制数据到应用程序的内存空间,或者简单地返回一个状态码。

应用程序恢复控制权,并继续执行。

需要注意的是,系统调用是一种开销较大的操作。当应用程序频繁调用系统调用时,会带来较大的性能开销。为了优化性能,一些操作系统提供了用户空间库,它们可以将多个系统调用合并为一个系统调用,或者将一些系统调用通过其他方式实现。

3.malloc 是如何分配内存的

malloc() 是 C 标准库中的函数,用于在程序运行时动态地分配内存。它的原型如下:

void* malloc(size_t size);

其中,size 参数指定要分配的内存大小,以字节为单位。

malloc() 函数的具体实现是由操作系统提供的,不同的操作系统可能有不同的实现方式。

一般来说,malloc() 函数使用一个空闲链表来管理可用的内存块。当程序调用 malloc() 函数时,它会在链表中寻找一个合适的内存块。如果链表中有大小足够的内存块,malloc() 函数就会将其中一个分配给程序,并将其从空闲链表中移除。如果链表中没有足够的内存块,malloc() 函数就会向操作系统请求更多的内存,一般是使用操作系统提供的系统调用(如 brk() 或 mmap())来完成这个操作。

由于 malloc() 函数可能会频繁地向操作系统请求内存,这可能会导致一些性能问题。为了解决这个问题,许多操作系统和 C 库都提供了一些优化技术,如预分配内存池、内存复用等,这些技术可以减少 malloc() 函数的调用次数,提高程序性能。

或者说:
malloc的工作原理如下:

首先,程序通过调用malloc函数向操作系统请求一块指定大小的内存空间。

操作系统会在进程的虚拟地址空间中找到一块足够大的空闲内存,并将其标记为已占用。

操作系统将这块内存的起始地址返回给程序。

malloc函数将返回的地址作为一个指针返回给程序员,程序员可以使用这个指针来访问这块内存。

malloc函数还可能会在返回指针之前,对内存进行一些初始化的操作,例如将内存中的所有位都设置为零。

需要注意的是,malloc分配的内存通常在程序员不再需要它时需要显式地释放,以便操作系统可以重新将其标记为可用空闲内存。否则,程序可能会遭受内存泄漏,导致系统资源浪费并可能导致程序崩溃。

下面是一个使用malloc动态分配内存的简单示例

#include <stdio.h>
#include <stdlib.h>

int main() {
    int n, i, sum = 0;
    int *nums;
    printf("请输入整数个数:");
    scanf("%d", &n);
    
    // 动态分配内存空间
    nums = (int*)malloc(n * sizeof(int));
    
    // 读入n个整数,并计算它们的和
    for (i = 0; i < n; i++) {
        printf("请输入第%d个整数:", i + 1);
        scanf("%d", &nums[i]);
        sum += nums[i];
    }
    
    // 输出计算结果
    printf("这%d个整数的和为%d\n", n, sum);
    
    // 释放内存空间
    free(nums);
    nums = NULL;
    return 0;
}

这个程序会提示用户输入整数的个数,然后动态分配一块大小为n个int类型变量的内存空间,读入n个整数,并计算它们的和。最后,程序会释放分配的内存空间,以避免内存泄漏。

需要注意的是,在使用malloc分配内存时,需要对返回的指针进行类型转换,以确保分配的内存大小正确,并且在使用完毕后需要及时调用free函数释放内存空间。

4.free是如何释放内存的,怎么确定释放内存的大小

"free" 是一个 Linux/Unix 系统下的命令,用于查看系统的内存使用情况并释放已经被占用的内存。具体的内存释放过程如下:

  1. 当进程使用 malloc 或者其他动态内存分配函数分配内存时,内存管理器会将对应的内存块标记为已占用状态。
  2. 当进程使用 free 函数释放内存时,内存管理器会将对应的内存块标记为可用状态,但是并不一定会立即返回给操作系统。
  3. 当内存管理器认为可以将一些已经被释放的内存块归还给操作系统时,它会将这些内存块返回给操作系统。

在 Linux/Unix 系统中,使用 free 命令可以查看当前系统的内存使用情况。该命令会列出系统中物理内存和交换空间的总量、已使用量、空闲量等信息。在 free 命令输出的第一行,可以看到一个叫做“free”的值,表示当前系统空闲的物理内存大小。

在程序中,可以使用一些工具来跟踪内存的分配和释放情况,从而确定已经释放的内存大小。例如,在 C/C++ 中,可以使用内存调试工具(如 valgrind)来跟踪内存的分配和释放情况,从而确定已经释放的内存大小。在其他编程语言中,也可以使用类似的工具来进行内存分析和调试。

当一个程序使用 malloc 或其他动态内存分配函数来分配内存时,内存管理器会为该程序保留一块连续的可用内存空间,这块内存空间的大小由程序请求的大小决定。假设程序请求分配了一块大小为 100 字节的内存空间,内存管理器会为该程序保留 100 字节的连续内存空间并将其标记为已占用状态。

当程序使用 free 函数释放该内存空间时,内存管理器会将其标记为可用状态,但是并不一定会立即将其归还给操作系统。此时,该内存空间变成了闲置的内存块,可以被后续的 malloc 或其他动态内存分配函数再次使用。如果程序需要分配一块大小为 50 字节的内存空间,内存管理器就可以将这个 100 字节的闲置内存块分割成两个部分,一个大小为 50 字节的内存块用于分配,另一个大小为 50 字节的闲置内存块继续保留。

当内存管理器认为可以将一些已经被释放的内存块归还给操作系统时,它会将这些内存块返回给操作系统。这个过程一般是由操作系统的内存回收机制来控制的,内存管理器会将一些已经被释放且长时间未被使用的内存块返回给操作系统,以便操作系统可以将这些内存块重新分配给其它使用

#include <stdlib.h>
#include <stdio.h>

int main() {
    int *arr = malloc(sizeof(int) * 10);
    if (arr == NULL) {
        printf("Memory allocation failed.\n");
        return 1;
    }
    // 释放内存
    free(arr);
    return 0;
}

当我们在程序中使用 malloc 函数来分配内存时,内存管理器会在堆区域中为我们分配一块指定大小的内存块,并将该内存块标记为已占用状态。例如,下面是一个简单的 C 代码示例:

#include <stdlib.h>
#include <stdio.h>

int main() {
    int *arr = malloc(sizeof(int) * 10);
    if (arr == NULL) {
        printf("Memory allocation failed.\n");
        return 1;
    }
    // 释放内存
    free(arr);
    return 0;
}

在上面的代码中,我们使用 malloc 函数分配了一块大小为 10 个 int 的内存块,并将其赋值给指针变量 arr。然后我们对该内存块进行了释放,使用了 free 函数。此时,该内存块会被标记为可用状态,但并不一定会立即返回给操作系统。这时候我们可以使用内存调试工具来检查该内存块是否已经被释放,以及该内存块的大小。

例如,使用 valgrind 工具来跟踪上述代码的内存分配情况,我们可以使用以下命令:

valgrind --leak-check=full ./a.out

运行该命令后,valgrind 会输出该程序的内存使用情况,其中包括已经分配的内存块、已经释放的内存块、尚未释放的内存块等。在本例中,valgrind 输出的信息如下:

==35671== HEAP SUMMARY:
==35671==     in use at exit: 0 bytes in 0 blocks
==35671==   total heap usage: 1 allocs, 1 frees, 40 bytes allocated
==35671==
==35671== All heap blocks were freed -- no leaks are possible

valgrind` 工具对程序进行了内存泄漏检测,并且程序退出时并没有未释放的内存块,因此没有发生内存泄漏。具体来说,上面的输出分为三部分:

  1. in use at exit:程序退出时还有多少字节的内存块处于已分配但未释放的状态。
  2. total heap usage:程序中总共进行了多少次堆内存分配和释放操作。
  3. All heap blocks were freed:程序退出时没有发生内存泄漏,即所有已分配的内存块都已经被释放。

在实际开发中,内存泄漏是一种常见的编程错误。当程序中的某些内存块被分配但未被释放时,这些内存块会一直占用系统资源,最终可能导致系统资源耗尽,从而导致程序崩溃或者系统崩溃。因此,我们应该始终注意在程序中正确使用堆内存,并使用内存调试工具来检测内存泄漏问题。

5.页面置换算法有哪些

6.cas是怎么样的一种同步机制

有关操作系统6道面试题的更多相关文章

  1. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  2. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  3. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  4. Hive SQL 五大经典面试题 - 2

    目录第1题连续问题分析:解法:第2题分组问题分析:解法:第3题间隔连续问题分析:解法:第4题打折日期交叉问题分析:解法:第5题同时在线问题分析:解法:第1题连续问题如下数据为蚂蚁森林中用户领取的减少碳排放量iddtlowcarbon10012021-12-1212310022021-12-124510012021-12-134310012021-12-134510012021-12-132310022021-12-144510012021-12-1423010022021-12-154510012021-12-1523.......找出连续3天及以上减少碳排放量在100以上的用户分析:遇到这类

  5. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  6. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

    我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

  7. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

  8. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  9. ruby - 在 Ruby 中是否有一种惯用的方法来操作 2 个数组? - 2

    a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],

  10. ruby-on-rails - 如何让 Rails View 返回其关联的操作名称? - 2

    我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam

随机推荐