线程、进程的联系(二)

Linux下运行Java程序: javac java
strace 跟踪进程、线程调用过程
Java进程/线程 映射到了Linux系统上

java跑在Linux上,跟踪一下Java进程,线程具体的系统调用,Linux系统本身的
fork和pthread_create调用对比一下,一模一样 
=> 
Java进程/线程 映射到了 Linux系统上
在Linux系统利用strace跟踪进程的启动过程,并打印   
java的Thread线程
clone(child_stack=0x7fc26391dff0, flags=CLONE_VM|CLONE_FS|
CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|
CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fc26391e9d0, tls=0x7fc26391e700, child_tidp
Linux的fork进程
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|
CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f15f4f809d0) = 4195
Linux的pthread_create线程
clone(child_stack=0x7f15f478bff0, flags=CLONE_VM|CLONE_FS|
CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|
 CLONE_SYSVSEM|CLONE_SETTLS|CLONE_P

Linux上 forx/pthread_create—》clone(标志位不一样)
Linux进程和线程最终都会映射到内核空间,内核空间都会创建PCB(内核控制块)Java/C++/PHP/Python ---->高级代码----编译 -----》汇编 ----》JVM虚拟机/OS/解释器
任何汇编语言写的代码:–》产生两个东西:数据、指令
Java/C++/PHP/Python —》 编译过程 —》 运行(操作系统/虚拟机/模拟器/解释器)
--------------------------------------------------------------------------------------------------------
int a = 10; a:存储10 的地址(0x984af)别名
虚拟地址:代码运行过程中看到的地址
物理地址:可以实实在在找到的
虚拟地址空间:(虚拟地址空间和虚拟地址不是一回事)
以Linux32位操作系统为例:2^32 = (4294967296)4G
Linux系统创建线程会分配内存空间大小为4G(虚拟地址空间)

进程间通信-共享内存原理

任何语言写的代码:   =====》    产生两个东西  :   指令   数据
Java/C++/PHP/Python   ===》   编译过程    =》   运行(操作系统/虚拟机/模拟器/解释器)
编译过程  =》  高级代码  =JVM虚拟机/操作系统 所能识别的汇编级指令
     int a = data;       
     a. data(地址)  =》 data  =》 寄存器
     b. 寄存器值    =》   (寻址)a
     
     int ret = func();
     a. 调用  func这个函数的地址
     b. func运行完了  =》  ret中
     上面的地址  =》 不可能写   =》  物理地址  =》 物理内存
     编译阶段,上面的数据和指令所需要的地址   =》   虚拟地址   =》  虚拟地址空间(区分虚拟内存)
     虚拟地址空间  =》  先忘记Java的内存模型
     基于X86体系的Linux 32位内核    《=    平台上去运行一个进程的时候,内核会给每一个进程
     都分配一个虚拟地址空间 2^32次方  =  4G
     ----------------------- 0x00000000
             预留区
     ----------------------- 0x08048000    
     .text(指令) .rodata(常量区)
     -----------------------
       .data    .bss (数据段)
     -----------------------
           .heap(堆)
     -----------------------
           .stack(栈)
     ----------------------- 0xC0000000上面部分(用户空间user space)默认3G,下面部分(内核空间, kernel space)默认1G
           内核
     ----------------------- 0xFFFFFFFF

(上面是进程的虚拟地址空间)
小贴士:

strace在linux下用来跟踪某个进程的系统调用
在solaris下,对应的是dtrace
在mac下,对应的命令是:dtruss
dtruss
dtruss - 使用DTrace来监视系统调用。
dtruss 在进程进行系统调用的时候,进行输出.它就像DTrace版的truss,和truss相比,它插入一些信息。值得注意的是只有在有root权限的终端下,可以使用DTrace。

执行并监控"df -h"命令的系统调用
# dtruss df -h
监控pid为1871的进程此时之后的系统调用
# dtruss -p 1871
监控所有名为 "tar"的进程
# dtruss -n tar
执行脚本test.sh,并监控子进程
# dtruss -f test.sh
执行"date" 命令并输出cpu消耗和剩余时间
# dtruss -eo date

所有的进程,都有自己的用户空间(用户空间是隔离的),内核空间是共享的

=> 进程线程(栈线程私有的,堆和数据段是线程共享的) Linux的进程和线程一样,进程和进程之间的用户空间是隔离的, 线程在内核空间和进程是一样的,但是线程没有自己的 用户空间,必须共享某个进程的用户空间
=》从系统调用上,也可以清晰的看到,进程创建的clone没有CLONE_VM, 线程创建的clone调用有CLONE_VM标志,代表共享父进程的虚拟地址空间
=》 程序运行的时候,执行指令和读写数据, 用的都是虚拟地址,
=》 指令和数据真正的还是要往物理内存上放的
下面是运行磁盘上的程序
DP(disk page)  
=》VP(虚拟地址空间上的地址) 
=》物理内存上放的
虚拟地址    =》 映射到  =》 物理地址(一块物理内存)
进程间通信方式
1、管道通信、消息队列、信号量
在内核空间开辟一个内存,一个线程写入,一个线程是可以读取到的(在内核空间建搞出一块内存来,你写了我能看见,我写了你也能看见)
进程不在一个地址空间中  所以 通信复杂  共享内核空间
同一个进程的所有线程都在一个地址空间中,共享堆和数据段,通信非常方便
2、共享空间
进程1   =》   自己的虚拟地址空间   =》(多级页表映射)   映射的是物理内存块3进程2   =》   自己的虚拟地址空间   =》(多级页表映射)   映射的是物理内存块3最终多个进程映射带同一块物理内存上去了

猜你喜欢

转载自blog.csdn.net/weixin_43301647/article/details/88932716