JVM内存模型

1.JVM整体结构图

  

JVM虚拟机分为: 堆,栈,程序计数器,元空间,本地方法栈,(另外包括类装载子系统执行引擎)

其中 堆,元空间是所有线程共享,栈,本地方方法栈,程序计数器是每个线程私有的。

堆主要分为 eden区,S0区,S1区,old区,今天不介绍。今天主要介绍一下JVM栈的结构

如上图所示,栈的组成是一个一个的栈帧组成的FILO队列,每个栈帧代表一个执行方法,

主要的栈帧分成 局部变量表,操作数栈,动态链接,方法出口。

    局部变量表: 主要用于存放每个方法的局部变量

    操作数栈:存放临时创建的数据

    动态链接:  栈要执行JVM字节码,主要是执行方法区.class加载的地址。

    方法出口:方法返回地址

程序计数器主要存放当前线程执行的JVM指令的id,通过javap -c xx.class 或者javap -v xx.class命令查看指令行号

如下图中的

 

2.JVM内存模型

上图就是jvm对一个initFlag变量的操作,分为8个步骤,分别对应8个原子操作

  JVM 8个原子操作,所有的java代码,都会转化成这8个原子操作
    read(读取):作用于主内存,它把变量值从主内存传送到线程的工作内存中,以便随后的load动作使用;
    load(载入):作用于工作内存,它把read操作的值放入工作内存中的变量副本中;
   use(使用):作用于工作内存,它把工作内存中的值传递给执行引擎,每当虚拟机遇到一个需要使用这个变量的指令时候,将会执行这个动作;
   assign(赋值):作用于工作内存,它把从执行引擎获取的值赋值给工作内存中的变量,每当虚拟机遇到一个给变量赋值的指令时候,执行该操作;
   store(存储):作用于工作内存,它把工作内存中的一个变量传送给主内存中,以备随后的write操作使用;
   write(写入):作用于主内存,它把store传送值放到主内存中的变量中。

   lock(锁定):作用于主内存,它把一个变量标记为一条线程独占状态;

   unlock(解锁):作用于主内存,它将一个处于锁定状态的变量释放出来,释放后的变量才能够被其他线程锁定;

lock原子操作的实现

  (1) MESI缓存一致性协议:一个线程对共享变量的修改,通过总线时,另一个线程通过总线嗅探机制,使自己的工作内存的对应的变量的缓存行失效,关于缓存行,可以查看这篇文章 https://my.oschina.net/manmao/blog/804161

  (2) 总线加锁; 对CPU到主存的总线进行加锁,其他的CPU无法访问。

   

  volatile 关键字底层实现

      volatile修饰的变量,在对改变量进行操作时,会在指令前加 lock修饰。volatile关键字只能保证数据多线程可见性,无法保证多线程操作的线程安全。volatile适用于一写多读的场景。

   synchrinized指令实现 monitorenter和monitorexit,当代码段处于加锁的区间,只能有一个线程可以执行,保证了线程的有序性和可见性。处于synchrinized修饰的代码段,变量都会里面更新到主内存和其他线程的的工作内存更新。

  并发编程的三大特性:原子性,可见性,有序性。 有序性:happen-before原则,as-if-serial语义(保证单线程计算结果相同)和指令重排序

 

 

JVM 状态指令

(1)查看GC情况
  * jstat -gcutil pid 1000 10
 S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
 0.00  20.19  86.29  12.91  97.85  96.99  59701  531.379   264   16.119  547.498
CCS:压缩类空间占比

  * jstat -gcnew pid 1000 10 (新生代大小)
TT:对象在新生代存活的次数
MTT:对象在新生代存活的最大次数
详情见
https://blog.csdn.net/maosijunzi/article/details/46049117

(2)jvm 线程栈情况,死锁情况
     jstack -l pid > /opt/tmp/threadDump.txt

     top -Hp pid 查看指定进程的线程的情况 

     printf "%x\n" tid 将 tid转化成 16进制展示

(3)jvm堆内存情况

    是否有内存泄漏,java内存堆栈(如果内存占用过多)
     jmap -histo:live pid查看堆内存中的对象数目

解析jstack 日志工具 
 https://fastthread.io/

关注点
内存占用超过 75% 单核 systemLoad (均值>0.8,峰值>1.2)
Full GC 单次(平均> 0.5s)
磁盘持续减少的幅度 > %1
流量(包括带宽,TPS等)显著增加


----------------JVM GC 日志----------------------
# -XX:+PrintGCDetails
33.125: [GC [DefNew:3324k->152k(3712k),0.0025925secs]3324k->152k(11904k),0.0031680secs]100.667: [Full GC [Tenured:0k->210k(10240k),0.0149142secs]4603k->210k(19456k), [Perm:2999k->2999k(21248k)],0.0150007secs] 
[Times: user=0.01sys=0.00real=0.02secs]

首先是最前面的33.125和100.667,代表的是GC发生的时间,这个数字的含义是从Java JVM启动以来经过的秒数。然后是日志开头的“[GC” 和“[Full GC”说明了这次垃圾收集的类型。接下来的“[DefNew”、"[Tenured"、“[Perm”表示GC发生的区域,而后面的"3324k->152k(3712k)"表示的是“GC前该区域已使用量->GC后该区域已使用量(该区域总量)”。而在后面的"3324k->152k(11904k)"表示的是“GC前Java堆已使用量->GC后Java堆的使用量(Java堆的总量)”。后面的0.0025925 secs等表示的是该区域GC的时间。而[Times: user=0.01 sys=0.00 real=0.02 secs]


*CMS收集
UseConcMarkSweepGC使用ParNew + CMS + Serial Old 的GC组合,Serial Old GC作为CMS GC出现Concurrent Mode Failure后的备用GC

UseParallelGC JVM运行在Server模式下的默认值,使用Parallel Scavenge GC + Serial Old 的GC组合

UseParallelOldGC 使用Parallel Scavenge GC + Parallel Old GC的GC组合

UseG1GC使用G1 GC来进行垃圾收集


 

      

转载于:https://my.oschina.net/manmao/blog/3100595

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值