Java性能调优面试-3

1、GC调优步骤

打印GC日志

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log

1、因为Minor GC执行时间非常短对性能影响不大,当MinorGC执行次数非常多且密集,也是需要分析。

2、正常FullGC间隔几十s或几分钟。此时仅仅间隔5s则不正常。

3、元空间:在程序刚加载时会从0增长,因为需加载各种jar包 而在程序正常执行时空间不变。

     此时增大元空间大小。

2、Java线程内存模型--并发编程JMM

a、CPU多核并发缓存架构

b、Java线程内存模型底层实现原理

c、CPU缓存一致性协议详解

d、深入汇编语言底层原理理解volatile

e、并发编程可见性,原子性与有序性

1、多核并发缓存架构

CPU缓存实际在CPU内部,数据从磁盘加载到主内存,再从主内存加载到CPU缓存。

 

2、JMM内存模型

Java线程内存模型跟CPU缓存模型类似,是基于CPU缓存模型来建立的,Java线程模型是标准化的,屏蔽掉了底层不同计算机的区别。

工作内存存储共享变量的副本,类似于CPU缓存,距离CPU近效率高。

initFlag作为共享变量,每个线程仅仅操作本地副本,不对其他线程可见。导致问题。

public class VolatileVisibilityTest {

    private static boolean initFlag = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("waiting data;");
                while(!initFlag){}
                System.out.println("===success====");
            }
        }).start();

        Thread.sleep(2000);

        new Thread(new Runnable() {
            @Override
            public void run() {
                prepareData();
            }
        }).start();
    }

    public static void prepareData(){
        System.out.println("prepareing data...");
        initFlag = true;
        System.out.println("prepare data end");
    }
}
waiting data;;;
prepareing data...
prepare data end

使用volatile解决可见性问题

public class VolatileVisibilityTest {

    private static volatile boolean initFlag = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("waiting data;");
                while(!initFlag){}
                System.out.println("===success====");
            }
        }).start();

        Thread.sleep(2000);

        new Thread(new Runnable() {
            @Override
            public void run() {
                prepareData();
            }
        }).start();
    }

    public static void prepareData(){
        System.out.println("prepareing data...");
        initFlag = true;
        System.out.println("prepare data end");
    }
}
waiting data;
prepareing data...
prepare data end
===success====

3、JMM详解

1、早期如何实现内存可见性问题?

  使用的总线加锁,性能太低:cpu从主内存读取数据到高速缓存,会在总线对这个数据加锁,这样其他cpu没法去读或写这个数据,直到cpu使用完数据释放锁之后其他cpu才能读取该数据。

即当第一个线程read读取数据之前,先对数据lock,线程执行完成并将最新值更新到主内存后,在unlock。己缓存里的数据失效。

2、现在使用什么方式?

MESI缓存一致性协议:多个CPU从主内存读取同一个数据到各自的高速缓存,当其中某个CPU修改了缓存里的数据,该数据会马上同步回主内存,其他CPU通过总线嗅探机制【类似于监听】可以感知到数据的变化,从而将自己缓存里的数据失效,然后重新从主内存读取到最新的值。

其中:总线是CPU与内存等硬件之间数据交换/通信的桥梁。

3、Volatile缓存可见性实现原理?

底层实现主要通过汇编lock前缀指令,它会3)锁定这块内存区域的缓存(缓存行锁定)并回写到主内存。

lock指令:1)会将当前处理器缓存行的数据立即写回系统主内存;2)这个写回主内存的操作会引起在其他CPU里缓存了该内存地址的数据无效(MESI协议

4、汇编语言分析

以下是对添加了volatile关键字后使用javap -v Math.class得到的汇编语言。

其中:lock是汇编关键字。     add dword ptr [rsp],Oh是汇编代码。

 add dword ptr [rsp],Oh 作用:就是将cpu修改的值assign到工作内存,将值复制给initFlag即上图中线程2的assign操作。

含有lock关键字的作用:cpu硬件会将当前处理器缓存行【cpu的工作内存】的数据立即写回系统主内存【即将 add dword ptr [rsp],Oh操作的值,不管该线程后面是否有其他代码,都会立即先将该值写回主内存】,然后在执行线程后面的代码。

lock三层含义:1、当工作内存的值一旦被修改,cpu硬件会立即将该值同步回主内存。同步回主内存过程中会经过总线,此时会触发缓存一致性协议以及cpu总线嗅探机制,其他线程监听到后通过MESI将本地内存的值置为失效状态。

2、在store之前加lock锁,即锁定这块内存的缓存。当执行unloack解锁后,其他线程才能读到主内存的值。

3、这个写回主内存的操作会引起在其他CPU里缓存了该内存地址的数据无效(MESI协议

5、并发编程三个特性

可见性、原子性、有序性

volatile保证可见性与有序性,但是不保证原子性,保证原子性需要借助synchronized这样的锁机制。

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值