本是一个外行人,偶然间入行也有4年,从当初小白一步一步走过来,期间迷茫过,奋斗过,虽然辛苦,但乐在其中。奈何,时间无情,今年也已经奔三。由于不爱交流,也不爱阿谀奉承,始终认为,做好自己的事就是行,但是人在社会总会有身不由己,身边总会有各种各样的笑面虎,亦或者哪些不懂管理的领导,但是为了生活,也要学会忍耐。
最近互联网寒冬,看着同行的伙伴们要么被裁要么也是战战兢兢,难免心中有些烦躁。不管寒冬如何寒冷,但是提升自己的技能总归是好的。为了安抚自己浮躁的内心,发现整理下自己以往所学,也是好的,用文字记录下来,于己于人都有利。
我们都知道,计算机中的资源可分为两大类:计算资源和储存资源。
PU是计算机的计算资源,它负责计算机的逻辑运算,但是CPU只有计算能力,却没有分配计算资源的能力,计算资源是否操作系统进程分配的。
储存资源就是内存,磁盘等这些记忆体,根据虚拟内存机制,我们知道,操作系统是用虚拟内存来管理这些物理内存的,一个物理内存地址对应一个虚拟内存地址,所有物理内存地址的集合叫做虚拟内存空间。对于计算机来说,32为的虚拟内存空间是最大4G,64为虚拟地址寻址最大理论上是16384GB(16TB)
进程表示一个可运行的程序,是计算机资源分配的最小单元(计算机可寻址的最小单元是8个bit或者字节)。 程序的代码段都在磁盘中,运行时加载到内存。
每个进程都包含用户区( 代码块,初始化区域,未初始化区域,堆,栈,)和内核区,在进程创建的过程中,程序的内容被映射到进程的虚拟地址空间,当程序运行时,操作系统加载这个程序的开始部门到物理内存中,然后操作系统处理程序的虚拟内存地址。
线程是进程的一个实体,是CPU最小调度单元,CPU调度只认识线程不认识进程。而线程又是怎么产生的呢?
其实在LINUX系统中,是没有线程这个概念的,只有内核调度实体,所谓线程只不过是一个轻量级进程。linux调用线程有两种方式,一种是fork系统调用(复制调用),一种是clone系统调用(共享调用)。
fork调用子进程是完全复制一份父类进程虚拟地址空间,采用的是一种写时复制原则,当fork创建子进程的时候,只是把指针指向父类进程地址,并没有真正创建新的地址空间,而当子进程真需要对物理地址进程操作时,才会复制一些物理资源来对其进程操作。这极大优化了程序的性能,同时子进程也真正拥有了自己的虚拟地址空间。
而clone调用则不一样,它创建子进程时,只是用指针指向父类虚拟地址空间,共用父类进程的物理地址空间,并不会单独在父类物理地址空间外开辟新的空间。既然子进程复用父类进程的物理地址空间,那么也就不用进行进程的上下文的切换,只需要记录子进程(线程)的线程ID,寄存器的值,以及栈数据等,不需要进程表和页的切换,这样就大大的提高了程序的运行效率。
线程的这种创建时一种对等性创建,并没有父子关系,他们同属于一个线程组,共用进程的地址空间。
而JVM本身是C语言编写的一个进程,当我们启程java程序的时候,本身启动的就是一个进程,那么JVM进程也应该由计算机进程的属性,但它又和平常的计算机进程不同,一般进程的垃圾回收由操作系统来进行回收,而JVM的垃圾由JVM本身进程回收。
当我们给JVM分配堆和栈内存时,启动后都会对应一个JVM进程的虚拟内存空间,JVM程序加载和一般程序加载一样,也是加载程序必要的部门,其他的 内存还是在虚拟内存空间,并没有分配到物理内存。当我们请求一个服务器资源时,其实服务器就为我们开启一个线程处理。但时JVM里面的线程和计算机的线程由什么关系?又是如何被CPU调度的呢?有空下篇文章分解。(一起学习,共勉)
来自《深入理解计算机系统》