面试题

jvm结构和垃圾回收机制

2019-08-14  本文已影响0人  Peakmain

Java内存管理机制

jvm结构.png

运行时区域

Java虚拟机在执行Java程序代码过程中会把它所管理的内存划分为若干个不同的数据区域。Java虚拟机所管理的内存将会包括以下几个运行时数据区域:
方法区,虚拟机栈(线程),本地方法栈,堆,程序计数器

程序计数器

Java虚拟机栈

public class Test {

   public static void main(String[] args) {
       Test test = new Test();
       test.compute();
   }

   int compute() {
       int a = 3;
       int b = 6;
       int c = (a + b)*2;
       return c;
   }
}

分析:首先我们会new Test()对象,放到堆内存中,随后会走Test 类中(也就是方法区中的类元信息Test.class)的compute方法,此方法会有个程序计数器,进入之后,首先将3加入到操作数栈中,下一步会将a加入到局部变量表中,并将3赋值给a,以此轮推,最后会将compute这个栈中的变量返回地址给main栈中,而compute方法这个寻找的过程也称为动态链接

本地方法栈

所有新生成的对象首先都是放在年轻代。首先它会进入到Eden区,当Eden区满时,还存活的对象将被复制到Survivor区(两个中其中一个,必须有一个是空闲的),只要移动到To区,里面有个值叫做分代年龄,这个值就会+1,当To满了,GC后还活着的会移动到From区,依次循环,当进行分代年龄到15以后,就会加入到老年代。永久代放的是静态变量和静态常量,类信息等

方法区

JMM内存模型

概述

AB通信过程:
1.线程A把本地内存A中更新过的共享变量刷新到主内存中去。2. 线程B到主内存中去读取线程A之前已更新过的共享变量。

一些方法

 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("等待数据...");
                while (!initFlag) {

                }
                System.out.println("======终于成功了");
            }
        }).start();
        Thread.sleep(2000);

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("准备数据...");
                initFlag = true;
                System.out.println("准备结束");
            }
        }).start();
    }

这里我加了一个volatile,我们来分析下没有加volatile的过程


image.png

首先主内存现在有个变量initFlag值为false,线程会从主内存读到(read)变量initFlag,随后将变量加载到写入线程的工作内存中,再将工作内存变量use进行内存变量的计算,再经过assign将变量赋值到工作内存中,store将工作内存数据写入主内存,write 将store过去的变量值赋值给主内存中的变量,这样主内存的工作变量就发生了变化。

JMM内存缓存不一致

volatile实现原理

 public static volatile int num=0;

    public static void main(String[] args) throws InterruptedException {
        Thread[] threads=new Thread[10];
        for (int i = 0; i < threads.length; i++) {
            threads[i]=new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 1000; i++) {
                        add();
                    }
                }
            });
            threads[i].start();

        }
        for (Thread thread : threads) {
            thread.join();
        }
        System.out.println(num);
    }

    private static synchronized void add() {
        num++;
    }

如果不加synchronized,其打印的值会小于10000,原因是volatile不是立即保证可见性,它有个写入主内存的过程,其他线程(B)等不及的会自己去拿原本的数据进行++运算,当这个线程(B)之前的线程(A)修改完主内存的值后,B已经运算完,但是此时失效了,就会导致原本++运算无效

垃圾收集器和内存分配策略

概述

算法

虚拟机栈(栈帧的本地变量表)中的引用对象
方法区中的类静态属性引用的对象
方法区中的常量引用对象
本地方法中JNI中的引用

四种引用

finalize()方法

回收方法区

垃圾收集算法

上一篇下一篇

猜你喜欢

热点阅读