面试总结二

JVM内存有哪些,哪些是线程共享的

线程独占:虚拟机栈,本地方法栈,程序计数器       线程共享:方法区。堆

哪些区会抛OOM异常

 OOM(Out of memory):就是内存溢出

  • 堆内存不足是最常见的 OOM 原因之一,抛出错误信息 java.lang.OutOfMemoryError:Java heap space,原因也不尽相同,可能是内存泄漏,也有可能是堆的大小设置不合理。

  • 对于虚拟机栈和本地方法栈,导致 OOM 一般为对方法自身不断的递归调用,且没有结束点,导致不断的压栈操作。类似这种情况,JVM 实际会抛出 StackOverFlowError , 但是如果 JVM 试图去拓展栈空间的时候,就会抛出 OOM.

  • 对于老版的 JDK, 因为永久代大小是有限的,并且 JVM 对老年代的内存回收非常不积极,所以当我们添加新的对象,老年代发生 OOM 的情况也非常常见。

  • 随着元数据区的引入,方法区内存已经不再那么窘迫,所以相应的 OOM 有所改观,出现 OOM,异常信息则变成了:“java.lang.OutOfMemoryError: Metaspace”。

volatile 怎么实现的可见性,为什么不能保证原子操作

Volatile是JVM提供的一个轻量级的同步机制。有两个作用:①:保证可见性(缓存一致性协议MESI,②:保证有序性(禁止指令重排优化)

Volatile是在汇编层面加Lock,使用缓存一致性协议(MESI)解决并发可见性的。MESI协议其实是一个变量在内存中的不同状态!首先cpu会根据共享变量是否带有Volatile字段,来决定是否使用MESI协议保证缓存一致性。 如果有Volatile,汇编层面会对变量加上Lock前缀,当一个线程修改变量的值后,会马上经过store、write等原子操作修改主内存的值(如果不加Lock前缀不会马上同步),为什么监听到修改会马上同步呢?就是为了触发cpu的嗅探机制,及时失效其他线程变量副本。cpu总线嗅探机制监听到这个变量被修改,就会把其他线程的变量副本由共享S置为无效I,当其他线程在使用变量副本时,发现其已经无效,就回去主内存中拿一个最新的值。

多线程环境下,有序性问题产生的主要原因就是执行重排优化,而Volatile的另一个作用就是禁止指令重排优化。具体是通过对Volatile修饰的变量增加内存屏障来完成的!内存屏障的主要工作原理为:通过在指令间插入一条内存屏障并禁止cpu对Volatile修饰的变量进行重排序,也就是说通过插入内存屏障禁止在内存屏障前后执行重排序优化!

为什么Volatile无法保证原子性?

比如,当前主内存的 count = 5,线程A 通过read、load等原子操作把 count = 5加载到本地内存中

  • 在执行引擎执行count++操作时,会有多步操作

  • ①:先初始化count = 5

  • ②:对count执行计算:count = 5+1

  • ③:把count=6 通过assign写入本地内存中

  • 刚好在①,②,③步中间,cpu被线程B抢去了,此时线程B的count也是5,执行count+1后,刷新主内存并通知了线程A.

  • 那么线程A原本的执行引擎中的count已经作废,会被丢弃,重新从主内存中获取最新的值,这样就平白无故丢了一次 +1 的操作,所以最后不等于200000!

  • 解决方案: 使用synchronized 既可以保证原子性 ,也可以保证可见性

以上来源于:https://blog.youkuaiyun.com/DFSETHTDFD/article/details/113438212

synchronized 与 lock区别

区别:  https://blog.youkuaiyun.com/DFSETHTDFD/article/details/113438423

TCP和UDP区别

进程间通信的几种方式,信号的特点

https://blog.youkuaiyun.com/DFSETHTDFD/article/details/113440412

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值