Java程序员的用户态内核态笔记

资讯 1年前 (2023) 千度导航
8 0 0

一. 前言

想起很多年前被问到了用户态和内核态的相关问题,当时一知半解,但是工作这么些年,也极少听到这个概念,直到最近碰到后,终于决定以Java的角度,真正的了解一下这2个状态的实际作用。

二. 内核态的概念和本质

2.1 概念与体现

内核主要控制计算机的硬件资源,并且提供运行环境给上层应用程序。

// 概念 : 
态是一种操作系统的运行级别. 
- 内核态通常是管理程序运行的状态,具有更高的级别,在这个状态可以执行所有的指令,以及使用所有的资源
- 用户态通常是用户应用的运行状态,权限较低,不可以使用特权指令,也不能直接使用系统资源,只能访问各自的存储空间

// 行为 : 
- 内核可以控制计算机的硬件资源,并且提供应用程序的运行环境
- 通过内核态调用内核的核心资源

// 原因 : 
- 权限的管理 : 避免高危指令执行出现问题,引发系统崩溃。高风险指令只能有限的开发给用户。
- 避免资源消耗 :系统资源是有限的,要减少访问系统资源的操作,避免过多的消耗


// 场地 : 
CPU 执行用户态和内核态指令,标识着当前CPU的运行态 (运行级别)

其他基础概念 :

  • 系统调用 : 内核为上层应用提供访问的接口,用于访问内核中的资源 系统调用是操作系统的最小功能资源
  • 库函数 : 是对系统调用的封装,再通过简单的接口呈现给用户
  • Shell : 特殊的应用程序,可以通过 Shell 命令方便的进行系统调用,并且可以集成到编程体系中

区别和对比

// 超级管理员与内核态的区别 : 
超级管理员是特殊的计算机用户,主要是软件层面的一种角色。 超级管理员不一定在内核态处理业务。

2.2 内核态和用户态分级

功能区别

// 用户态功能 :
汇编 / 编译 / 编辑 / shell  / API 函数 (读写)

// 内核态功能 : 
进程管理 / 存储管理 / 文件管理 / 设备管理
Java程序员的用户态内核态笔记

2.3 用户态到内核态的切换场景

用户态 -> 内核态

  • 系统调用 :通过任何途径进行系统调用的时候,都会发生2态的装欢
  • 异常事件 :当发生一些系统级别的异常事件时 , CPU 会处理异常事件,从而发生切换
  • 外围系统中断 : 当外围系统完成后,会向 CPU 发送中断信号 ,此时 CPU 开始处理中断信号

内核态 -> 用户态

  • 设置程序状态字 PSW

总结 :内核态可以随意切换到用户态。用户态只能通过系统调用和中断来到内核态

三. Java 中内核态和用户态的涉及情况

3.1 Java 上内核态的使用

  • 线程进行上下文切换,堵塞,时间片使用完成,睡眠等操作时,会发生多态和切换
  • 线程切换的调度器在内核中
  • 线程切换和态切换没有直接关系,但是多数切换都是放在内核中进行

3.2 多态转换的流程

  • 设置处理器至内核态。
  • 保存当前寄存器(栈指针、程序计数器、通用寄存器)。
  • 将栈指针设置指向内核栈地址。
  • 将程序计数器设置为一个事先约定的地址上,该地址上存放的是系统调用处理程序的起始地址。
  • 而之后从内核态返回用户态时,又会进行类似的工作。

3.2 多态切换会有哪些风险

无锁并发编程。多线程竞争锁时,加锁、释放锁会导致比较多的上下文切换 CAS算法。使用CAS避免加锁,避免阻塞线程 使用最少的线程。避免创建不需要的线程协程。在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换

切换耗时原因 :

当发生切换时, 第一个操作点就是保存现场,再在另外的态中恢复现场。这种时间消耗不多,但是如果调用非常频繁,耗时累加也是很多的。

第二个操作点时 ,当切换内核态的时候,内核需要进行额外的校验,检查是否需要调度等,也会占用额外的耗时。

四. JVM 和 Linux 关于内核态和用户态的边界

4.1 底层角度出发

内核栈和内存的隔离

  • 堆和栈和Java角度是一致的,在Linux 中,进程/线程都是通过一个 task_struct的实例描述 task_struct`中有一个 stack 用于保存内核栈地址
  • 用户态的堆、栈对应用户进程虚拟地址空间里的一个区域
  • 内核通过虚拟地址访问权限来限制用户程序访问内存地址

4.2 JVM 层面分析

空间划分 :

  • 内核空间 :最高的 1G 字节(从虚拟地址 0xC0000000 到 0xFFFFFFFF)由内核态使用
  • 用户空间 :较低的 3G 字节(从虚拟地址 0x00000000 到 0xBFFFFFFF)由各个进程使用

进程上下文

  • 在上下文中,用户进程会将参数传递给内核,同时内核会保存寄存器值和当前环境信息 用户级上下文: 正文、数据、用户堆栈以及共享存储区 寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP) 系统级上下文: 进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈

PS : 这里就存在上下文切换的场景

Java 中涉及切换的操作

  • IO 操作会直接调用系统硬件
  • 线程操作 ,线程创建切换直接涉及到多个态的转换
  • 创建对象等场景的内存分配

4.3 开发中对内核态和用户态的使用

  • C语言中的 sork() 来分配内存
  • print() 函数会调用 wirte() 进行系统调用输出字符串
  • 申请动态的内存空间

总结

看了很多文档,还是感觉一知半解,没有从实践角度弄懂,到底他们在业务中有什么影响。只能说大概了解了其中的组成。

版权声明:千度导航 发表于 2023年2月18日 20:21。
转载请注明:Java程序员的用户态内核态笔记 | 千度百科

相关文章