JVM虚拟机学习:
jvm内存区域:
堆:
栈(线程):线程栈,为每一个线程在栈里面分配内存空间。每一个线程分配一个栈内存空间,同时一个线程中的一个方法又会在这个栈内存空间站细粒度的分配一个栈帧空间。
局部变量在使用完成之后会销毁给其分配的内存空间。
线程中用new出来的对象、或者其他对象,会在栈里面存储该对象在堆里面的地址信息,也就是堆对象的指针
本地方法栈:
方法区(元空间):
程序计数器:每一个线程运行时都会在栈内存中分配一块程序技计数器的内存,程序计数器用来记录程序运行到哪个位置,或者说哪一行。
为什么要设计程序计数器或者说程序计数器的作用是什么?
程序计数器的作用是记录他所对应的线程的执行位置。在多线程的情况下,有可能该线程未执行完毕就被挂起(如wait:),在他重新分配到cpu的时候从程序计数器里面读取到
它之前执行到的位置,再继续执行。
字节码存储引擎会去修改程序计数器中的值。
native修饰的方法是本地方法,使用c++写的。调用本地方法时调用的是dll文件。如果调用到了本地方法会在本地方法栈中分配一块空间
GCROOTS:线程栈的本地变量、静态变量,本地方法栈的变量等。
>> 相当于除以2取下整。 3 >> 2 = 1
<< 相当于左移动一位。 转换为2进制再向左边移动一位
jdk自带的jvm监控工具: jvisualvm 需要下载插件即可监视visual GC
为什么要jvm调优?
减少stw(stop the world)的时间。减少full GC的次数,甚至不让其发生fullGC。
将年轻代的大小设置大一点,保持让其每次minor GC移动到survival区的数据量的大小不到survival区大小的一半,就能够尽量的减少full GC的次数。
如果survival区中的对象大小超过了survival区大小的一半,就会直接将其放入老年代。
jmm:
一个线程 + 线程的缓存区 + 主内存(可以理解问栈或者堆))
多个线程中的同一个对象数据都是通过对主内存中的数据进行copy,放在线程的缓存区的。
如果有一个线程对该数据进行了修改,会先修改线程缓存中的值然后在写会主内存,其他线程读取的数据还是原来的数据,此时就会造成数据不一致性。
解决方案一: 总线加锁。对经过总线的每一个数据加锁。缺点:多线程读写的时候,只有一条线程能同时对这个数据进行操作。
解决方案二:volatile关键字。
1.每个jmm会对总线上进行监听,只要线程缓存中的数据有变化就会将jmm缓存区中的数据设置为失效,重新去主内存中获取。
2.遵循MESI缓存一致协议
3.每一个线程都是在store的时候将数据加锁。
jmm内存数据的获取: read -> load ->use ->(if change) -> store(volatile会对对象进行lock) -> write
java Jvm原理以及常见的jvm监听工具
最新推荐文章于 2023-04-02 07:45:00 发布