CPU高速缓存、内核态与用户态、堆外内存、零拷贝简述

CPU缓存结构

在CPU上集成了多级缓存架构,常见的为三级缓存结构

  • L1 Cache,分为数据缓存和指令缓存,逻辑核独占
  • L2 Cache,物理核独占,逻辑核共享
  • L3 Cache,所有物理核共享

存储器存储空间大小:内存>L3>L2>L1>寄存器;
存储器速度快慢排序:寄存器>L1>L2>L3>内存;
缓存是由最小的存储区块-缓存行(cacheline)组成,缓存行大小通常为64byte
比如你的L1缓存大小是512kb,而cacheline = 64byte,那么就是L1里有512 * 1024/64个cacheline

在这里插入图片描述

CPU读取存储器数据过程

CPU先从寄存器读取,若没有,则从L1中读取,LI没有则从L2读取,L2没有则从L3读取,L3没有则从内存中读取,读取到后,再向上一层层复制到缓存中,即将数据从内存复制到L3,从L3复制到L2,再从L2复制到L1,L1复制到寄存器,最后CPU从寄存器中读取数据

CPU高速缓存

CPU高速发展,然而内存和硬盘的发展速度远远不及CPU,在CPU访问存储设备时,无论是存取数据抑或存取指令,都趋于聚集在一片连续的区域中,这就被称为局部性原理。

  • 时间局部性(Temporal Locality):
    如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。 比如循环、递归、方法的反复调用等。 简单说就是将数据复制到寄存器使用完后,有可能该数据还会被再次引用,因此不会立即丢弃
  • 空间局部性(Spatial Locality):
    如果一个存储器的位置被引用,那么将来他附近的位置也会被引用。 比如顺序执行的代码、连续创建的两个对象、数组等,简单说就是CPU从内存中获取数据时,会将该数据附近连续位置的数据也一起复制到缓存中,这样会减少和内存的直接交互
高速缓存的CPU执行计算的流程
  • 程序以及数据被加载到主内存
  • 指令和数据被加载到CPU的高速缓存
  • CPU执行指令,把结果写到高速缓存
  • 高速缓存中的数据写回主内存
CPU上下文切换

CPU在处理线程任务时会进行高速切换,让使用者感觉到这些线程在同时执行,即并发的概念。
CPU是采用时间片轮询的方式来执行的,比如两个线程T1、T2,CPU各分配的是10ns(纳秒)、50ns,那么当CPU将T1执行10ns后会将T1运行的中间状态保存到上下文中,再去执行T2。
在这里插入图片描述

操作系统内存空间

操作系统有用户空间与内核空间两个概念,目的也是为了做到程序运行安全隔离与稳定。进程与线程只能运行在用户方式(usermode)或内核方式(kernelmode)下。
用户程序运行在用户方式下,而系统调用运行在内核方式下。在这两种方式下所用的堆栈不一样:用户方式下用的是一般的堆栈(用户空间的堆栈),而内核方式下用的是固定大小的堆栈(内核空间的堆栈,一 般为一个内存页的大小),即每个进程与线程其实有两个堆栈,分别运行于用户态内核态

内核线程模型(KLT)

系统内核管理线程(KLT),内核保存线程的状态和上下文信息,线程阻塞不会引起进程阻塞。在多处理器系统上,多线程在多处理器上并行运行。线程的创建、调度和管理由内核完成,效率比ULT要慢,比进程操作快。
在这里插入图片描述

用户线程模型(ULT)

用户程序实现,不依赖操作系统核心,应用提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/内核态切换,速度快。内核对ULT无感知,线程阻塞则进程(包括它的所有线程)阻塞。
在这里插入图片描述

  • 我们的JVM采用的是内核线程模型KLT,如下代码,创建200个线程,我们可以在电脑CPU的线程数据看到会增加200个
    public static void main(String[] args) {

        for (int i=0;i<200;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }

直接内存(堆外内存)

本机内存中除了JVM堆内存以外的内存区域,称为直接内存。直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,某些情况下这部分内存也会被频繁地使用,而且也可能导致OutOfMemoryError异常出现。Java里用DirectByteBuffer可以分配一块直接内存(堆外内存),元空间对应的内存也叫作直接内存,它们对应的都是机器的物理内存。
在这里插入图片描述

  • 直接内存申请较慢,但访问效率高
    java虚拟机实现上,本地IO会直接操作直接内存(直接内存=>系统调用=>硬盘/网卡),而非直接内存则需要二次拷贝(堆内存=>直接内存=>系统调用=>硬盘/网卡)
  • 直接内存的回收
    ByteBuffer buffer = ByteBuffer.allocateDirect(1000) // 创建直接内存
    buffer:局部变量
    ByteBuffer.allocateDirect:返回DirectByteBuffer对象
    unsafe.allocateMemory:调用本地方法,分配直接内存
    引用关系:buffer引用ByteBuffer.allocateDirect返回的DirectByteBuffer对象,DirectByteBuffer对象又引用直接内存
  • 1、当方法结束后,buffer局部变量被销毁,DirectByteBuffer对象处理游离状态,变成垃圾对象,下一次GC会回收掉DirectByteBuffer对象,此时直接内存无引用,则直接内存也会被回收掉
  • 2、Bits.reserveMemory(size, cap) 分配内存前先判断
  • 2.1、是否有足够的直接内存空间分配,可通过-XX:MaxDirectMemorySize=参数指定直接内存最大可分配空间,如果不指定默认为最大堆内存大小
  • 2.2、在分配直接内存时如果发现空间不够会显示调用System.gc()触发一次full gc回收掉一部分无用的直接内存的引用对象,同时直接内存也会被释放掉
  • 3、Cleaner.create(this, new Deallocator(base, size, cap)) 内存回收处理函数
    当直接内存引用对象被GC清理掉时,会提前调用这里注册的释放直接内存的Deallocator线程对象的run方法

零拷贝

零拷贝并不是没有拷贝,只是减少了用户空间和内核空间之间数据的相互拷贝
在这里插入图片描述
JVM内存位于用户空间、而操作系统函数则位于内核空间,在读写数据时,会涉及到多次空间切换和数据拷贝

堆内存服务端读写数据流程 图1

  • 读数据:
    1、数据会先发送到服务端内核空间的socket缓冲区
    2、由用户空间切换到内核空间,将数据从socket缓冲区拷贝到直接内存
    3、将数据从内核空间的直接内存拷贝到用户空间的JVM内存
    4、由内核空间切换至用户空间,在JVM内存中对数据进行修改处理
  • 写数据:
    1、由用户空间切换至内核空间,将JVM内存中的对象拷贝至直接内存
    2、从直接内存拷贝至socket缓存区

直接内存服务端读写数据流程 图2

  • 读数据:
    1、数据会先发送到服务端内核空间的socket缓冲区
    2、由用户空间切换到内核空间,将数据从socket缓冲区拷贝到直接内存
    3、由内核空间切换至用户空间,在JVM内存中通过地址的引用操作直接内存
  • 写数据:
    1、由用户空间切换至内核空间,此时直接内存中的数据便是操作后的数据
    2、从直接内存拷贝至socket缓存区

mmap文件映射机制

用户态不再保存文件的内容,而只保存文件的映射,包括文件的内存起始地址,文件大小等。真实的数据,也不需要在用户态留存,可以直接通过操作映射,在内核态完成数据复制。如图2,用户态只保留数据的引用。
mmap机制适合操作小文件,如果文件太大,映射信息也会过大,容易造成很多问题。通常mmap机制建议的映射文件大小不要超过2G 。

sendFile机制

在内核态拷贝过程中,并不直接拷贝文件的内容,而是只拷贝一个带有文件位置和长度等信息的文件描述符FD,这样就大大减少了需要传递的数据。而真实的数据内容,会交由DMA控制器,从页缓存中打包异步发送到socket中。
sendfile机制在内核态直接完成了数据的复制,不需要用户态的参与,所以这种机制的传输效率是非常稳定的。sendfile机制非常适合大数据的复制转移。
在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值