JavaJVM_操作系统

目录
  • 操作系统还像程序员提供了一层接口,叫做系统呼叫层,程序员可以面向这一层的接口编程,来实现对计算机的控制,而不同的操作系统 (或者说不同的 CPU 架构) 所提供的接口都是不一样的
  • JVM 虚拟机相当于在操作系统之上建立的一个虚拟的计算机。其中内存结构可以看出来,jvm 中 pc 寄存器,栈,堆,元空间和常量池对应计算机的处理器和内存。JVM 能操作所有操作系统,向上提供统一接口,也就是 JavaAPI,开发者只需要面向 JVM (JavaAPI) 编程,至于 JVM 是如何各种不同的操作系统打交道开发者完全不用管。

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/705292.jpg

1. 操作系统&CPU&指令集

首先操作系统还是普通的应用程序最终都得转化到二进制代码才能够被 cpu 所处理。而用高级语言编写的普通应用程序都必须经过编译器编译后成为二进制代码(指令)才能运行。而不同的 cpu 所实现的指令集不同,所以不同的指令集对应的编译器也不尽相同,编译器不同,相同的高级语言程序经过编译后所得到的二进制代码也不同。

2. 内存操作

内存首先是建立操作系统的内存模型,然后其他内存模型都建立在操作系统的内存模型之上或者跟操作系统内存模型有关。比如 JVM 的内存模型,当我们操作数据的时候,JVM 内存模型发生变化,从而控制操作系统,操作系统跟 CPU 之间完成非常复杂的沟通,然后得出结果,从 IO 送出信号。而这一切的一切在计算机内部都是所谓的二进制在运行,再向下一点,就是无数个高低电平的变化。

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/bb.jpeg

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/bb-164810745219815.jpeg

从软件层面上, class 文件被加载进虚拟机后,类信息会存放在方法区,在实际运行的时候会执行方法区中的代码,在 JVM 中所有的线程共享堆内存和方法区,而每个线程有自己独立的 Java 方法栈本地方法栈(面向 native 方法)PC 寄存器(存放线程执行位置),当调用一个方法的时候, Java 虚拟机会在当前线程对应的方法栈中压入一个栈帧,用来存放 Java 字节码操作数以及局部变量,这个方法执行完会弹出栈帧,一个线程会连续执行多个方法,对应不同的栈帧的压入和弹出,压入栈帧后就是 JVM 解释执行的过程了。

3. 内存模型

现代计算机多采用虚拟存储技术,虚拟存储让每个进程以为自己独占整个内存空间,其实这个虚拟空间是主存和磁盘的抽象,这样的好处是,每个进程拥有一致的虚拟地址空间,简化了内存管理,进程不需要和其他进程竞争内存空间

因为他是独占的,也保护了各自进程不被其他进程破坏,另外,他把主存看成磁盘的一个缓存,主存中仅保存活动的程序段和数据段当主存中不存在数据的时候发生缺页中断,然后从磁盘加载进来,当物理内存不足的时候会发生 swap 到磁盘。页表保存了虚拟地址和物理地址的映射,页表是一个数组,每个元素为一个页的映射关系,这个映射关系可能是和主存地址,也可能和磁盘,页表存储在主存,我们将存储在高速缓冲区 cache 中的页表称为快表 TLAB 。

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/bb-164810834107217.jpeg

4. 内存映射

  • 读取文件的流程为,先通过系统调用从磁盘读取数据,存入操作系统的内核缓冲区,然后在从内核缓冲区拷贝到用户空间
  • 内存映射,是将磁盘文件直接映射到用户的虚拟存储空间中,通过页表维护虚拟地址到磁盘的映射

https://lddpicture.oss-cn-beijing.aliyuncs.com/picture/bb-164810856955419.jpeg

5. 线程模型

JVM 中的线程和内核线程是一一对应的,线程的调度完全交给了内核,当调用 Thread.run 的时候,就会通过系统调用 fork () 创建一个内核线程,这个方法会在用户态和内核态之间进行切换,性能没有在用户态实现线程高,当然由于直接使用内核线程,所以能够创建的最大线程数也受内核控制。目前 Linux 上 的线程模型为 NPTL ( Native POSIX Thread Library),他使用一对一模式,兼容 POSIX 标准,没有使用管理线程,可以更好地在多核 CPU 上运行。

对进程而言,就三种状态,就绪,运行,阻塞,而在 JVM 中,阻塞有四种类型,我们可以通过 jstack 生成 dump 文件查看线程的状态。

  • BLOCKED (on object monitor) 通过 synchronized (obj) 同步块获取锁的时候,等待其他线程释放对象锁,dump 文件会显示 waiting to lock <0x00000000e1c9f108>
  • TIMED WAITING (on object monitor) 和 WAITING (on object monitor) 在获取锁后,调用了 object.wait () 等待其他线程调用 object.notify (),两者区别是是否带超时时间
  • TIMED WAITING (sleeping) 程序调用了 thread.sleep (),这里如果 sleep (0) 不会进入阻塞状态,会直接从运行转换为就绪
  • TIMED WAITING (parking) 和 WAITING (parking) 程序调用了 Unsafe.park (),线程被挂起,等待某个条件发生,waiting on condition

Resource

0%