7/30打卡 JVM复习

7/30 JVM(空间系问题)

前言

想知道JVM如何组成吗?想知道GC算法吗?先说说一段脍炙人口的话:

因为空间(EDEN区)不足所以触发Minor GC,因为老年代空间不足所以触发Major GC,垃圾回收由此打开。

本章的知识本质上都是空间问题,

对于JVM重点在于每一组成部分(重点在方法区和堆栈)的功能。

对于GC,因为空间不足交给Minor GC,再不足交给Major GC,再不行Stop the world慢慢消化处理,再不行那就抛异常、奔溃。

一、基本梳理

JVM主要由程序计数器,栈(本地方法栈和虚拟机栈),堆,方法区(常量池在方法区)组成。

不同JVM上的方法区实现肯定不同,那么以Sun公司举例,它的方法区在1.8以前使用永久代(HotSpot)来实现方法区这一概念,现在使用元空间。

可设置基本参数:方法区初始大小:PermSize;方法区最大大小:MaxPermSize。

二、基本作用

堆存放对象,栈存放对象的引用,方法区存放常量池,常量,各种方法,静态变量。

三、永久代–》元空间

存储位置不同:永久代是堆的一部分;元空间属于本地内存。

存储内容不同:元空间存储元信息,将静态变量和常量池并入堆中。相当于永久代的数据分到了堆和元空间。

四、常量池

Class文件常量池指编译生成的Class字节码文件,存放编译期间生成的各种字面量和符号引用,内容在类加载后再后进入方法取得运行时常量池中存放。

运行时常量池是方法取得一部分class文件常量池–》类加载后进入方法区的运行时常量池中存放。运行时常量池用来索引和查找字段和方法名称和描述符的。

字符串常量池是全局的,给String类型的引用赋值的时候会先执行这个指令,看常量池中是否存在这个字符串对象的引用,若有直接返回这个引用,若没有就在堆里创建这个字符串对象并在字符串常量池中记录下这个引用。JVM中Byte,Short,Integer,Long,Character只在对应值[-128,127]时才会使用缓冲池,否则仍然创建一个对象(常见题目包装类)。jdk8移除永久代,所以字符串常量池就存在本地内存当中了,存储的也只是引用。

总结:首先必须知道堆、栈、程序计数器、方法区的概念(存放),其次对于方法区要有一定的了解。对于JDK版本的变化要知道永久代和元空间基本区别。(元空间属于本地内存,永久代是堆的一部分,永久代的数据被分到了堆和元空间)

8/5补充

1、JVM调优可以使用,jps:虚拟机进程状态工具,jstat:虚拟机统计信息监视工具,jmap:Java内存映射工具,jinfo:Java配置信息工具等。

2、GC算法可以通过ReferenceCount或者根可达算法,但是为避免循环引用的问题,所以Java中采用根可达算法。GC分为新生代、老年代、永久代(或元空间)。

永久代:废弃常量或者

3、Class在被加载的时候被放入永久区域。它和和存放实例的区域不同,GC不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的Class的增多而胀满,最终抛出OOM异常。在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。

4、主要三种算法分为copying,标记整理,标记清除。

垃圾回收的时机

Minor GC 触发条件:

创建对象在Eden区,且Eden区空间不足

Major GC触发条件:

对象存放在老年代,而老年代空间不足,都会触发,包括

a.新生代年老对象晋升

b.大对象直接进入老年代。

c.Minor GC的分配担保机制,在发生Minor GC之前,如果老年代最大的连续空间小于新生代所有对象的总空间,有可能会触发Major GC

d.CMS无法处理浮动垃圾,可能会导致另一次full GC

Volatile

https://www.cnblogs.com/dolphin0520/p/3920373.html

内存模型的相关概念

大家都知道,计算机在执行程序时,每条指令都是在 CPU 中执行的,而执行指令过程中,势必涉及到数据的读取和写入。由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过程跟 CPU 执行指令的速度比起来要慢的多,因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度。因此在 CPU 里面就有了高速缓存。
也就是,当程序在运行过程中,会将运算需要的数据从主存复制一份到 CPU 的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。

经典案例:i = i + 1;

多线程中可能最终结果 i 的值是 1,而不是 2。这就是著名的缓存一致性问题。通常称这种被多个线程访问的变量为共享变量
也就是说,如果一个变量在多个CPU中都存在缓存(一般在多线程编程时才会出现),那么就可能存在缓存不一致的问题。

解决方案1:直接加锁

解决方案2(优化):只要将分散在各地的共享变量,其中一份线程修改的时候通知让其他线程查看数据无效化,让他们都从内存中去找,就不会出现问题了。

并发程序三问题:原子性,可见性,有序性问题

原子性:事务要不不做要不都做。银行转账案例。

可见性:

//线程1执行的代码
int i = 0;
i = 10;

//线程2执行的代码
j = i;

j可能为0,就是典型的不可见线程1的修改。

有序性:多线程下的问题:例如i++,new一个对象

Volatile

Java提供了 volatile 关键字来保证可见性。

可见性

当一个共享变量被 volatile 修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。另外,通过 synchronized 和 Lock 也能够保证可见性,synchronized 和 Lock 能保证同一时刻只有一个线程获取锁然后执行同步代码

有序性

8 条原则摘自《深入理解Java虚拟机》

  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作
  • 锁定规则:一个 unLock 操作先行发生于后面对同一个锁额 lock 操作
  • volatile 变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
  • 传递规则:如果操作 A 先行发生于操作 B,而操作 B 又先行发生于操作 C,则可以得出操作 A 先行发生于操作C
  • 线程启动规则:Thread 对象的 start() 方法先行发生于此线程的每个一个动作
  • 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过 Thread.join() 方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
  • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始

###内存屏障volatile

volatile保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
禁止进行指令重排序。

下面这段话摘自《深入理解Java虚拟机》

观察加入 volatile 关键字和没有加入 volatile 关键字时所生成的汇编代码发现,加入 volatile 关键字时,会多出一个 lock 前缀指令

lock 前缀指令实际上相当于一个内存屏障(也称内存栅栏),内存屏障会提供 3 个功能:

  • 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;

  • 它会强制将对缓存的修改操作立即写入主存;

  • 如果是写操作,它会导致其他 CPU 中对应的缓存行无效。

总结

核心:内存屏障,确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面,主要表现特性:

可见性(快速更新内存中的值,让其他线程从内存中直接取而不是从高速缓存中取值);

禁止指令重排序(保证多线程下的执行顺序)。

注意:因为不保证原子性(i++),所以volatile适用于确定保证原子性的场景下,例如状态标志量,双重校验锁。

进阶回答:

lock 前缀指令实际上相当于一个内存屏障(也称内存栅栏),内存屏障会提供 3 个功能:

  • 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
  • 它会强制将对缓存的修改操作立即写入主存;
  • 如果是写操作,它会导致其他 CPU 中对应的缓存行无效。

实习问题:qlik里面出现了字段描述一致,但是信息不同的小小问题,可能是一期二期不断修改数据库弃用字段和现在新加的数据字段的冲突。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HkmAnwfH-1599990058726)(assets/冗余度.PNG)]

接下来做一下测试的题目

即写入主存;

  • 如果是写操作,它会导致其他 CPU 中对应的缓存行无效。

实习问题:qlik里面出现了字段描述一致,但是信息不同的小小问题,可能是一期二期不断修改数据库弃用字段和现在新加的数据字段的冲突。

[外链图片转存中…(img-HkmAnwfH-1599990058726)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值