深入理解JVM虚拟机

类加载器

加载器启动类加载器 Bootstrap

拓展类加载器 Extension

应用程序类加载器 AppClassLoader

双亲委派机制

自己写了一个类 会先去最高层的类加载器加载 防止污染源代码

方法区

所有线程共享 存在垃圾回收

方法区绝对不是存方法的地方

方法区存储了每一个类的结构信息 例如运行时的方法。字段。构造方法等的字节码内容

stack栈

栈管运行 堆管存储

栈中的数据所有线程不共享 不存在垃圾回收 线程结束就over

占中存放:8中基本类型+对象的引用变量+实例方法

本地变量:输入参数 返回参数 定义参数

记录出栈入栈操作

栈内存溢出会发生 java.lang.StackOverflowError错误

堆栈方法区关系

深入理解JVM虚拟机_第1张图片

堆内存逻辑上分为三部分 物理上分为1和2俩个部分

1新生代

​ 1.1伊甸园区

​ 1.2 幸存者0区

​ 1.3幸存者1区

2老年代

3元空间/永久代 1.8之后永久区变成了元空间

深入理解JVM虚拟机_第2张图片
深入理解JVM虚拟机_第3张图片

所有新创建出来的对象都会存在于伊甸区 当伊甸区满了之后触发YGC垃圾回收 没有被回收的对象进入幸存区 经历15次GC还没被清理的对象进入老年代区,老年代区满了之后 触发 FGC(Full GC) 清理完之后还是没有空间 报出 OOM异常

幸存区交换:

当伊甸区满了之后 会触发GC 此时GC不仅回收伊甸区 还会回收俩个幸存区,GC之后 必然清空伊甸区和幸存区 活下来的对象进入幸存1区,幸存1区和幸存0区会交换 谁空谁是幸存1区 每次没有被清理的对象的年龄都会+1 达到15次之后转移到老年代

堆参数调优

1.7之前永久代使用JVM堆内存 1.8之后元空间使用物理内存

默认JVM堆内存大小是物理内存的一办

-Xms 设置初始内存大小 默认为物理内存 1/64

-Xmx 设置对大内存 默认为物理内存的1/4

-XX:+printGCDetails 输出详细 GC处理日志

查看当前内存大小

public class Test {
    public  static void main(String[] args) {
        long max = Runtime.getRuntime().maxMemory();
        long init = Runtime.getRuntime().totalMemory();
        System.out.println("最大内存"+(max/1024/1024)+"MB");
        System.out.println("初始内存"+(init/1024/1024)+"MB");
        //最大内存1790MB
        //初始内存121MB
    }
}

在生产环境 中 初始内存和最大内存必须调成一样,为什么?避免内存忽高忽低造成卡顿
深入理解JVM虚拟机_第4张图片

日志信息解释

深入理解JVM虚拟机_第5张图片

GC和fullGC

Minor GC只针对yong区进行垃圾回收 因为大多数对象存活率都不高 所以FC非常频繁

fullGC 针对老年区的垃圾回收 经常会伴随出现至少一次Minor GC 但不是绝对的 FullGC 比 Mainor GC 慢十倍

GC(分代收集算法)

次数上频繁收集yong区

次数上较少收集old区

基本不动元空间

GC4算法

引用计数法:

如果一个对象有n个引用 那么计数为n 当n=0也就是没人引用的时候回收。缺点:每次对对象赋值时都要引用计数器,且计数器本身也有消耗

复制算法:

年轻代gc采用复制算法 对象在幸存区熬过一次 年龄+1 当年龄达到15(默认 可以修改但不能超过15)将会被转移到老年代 ,复制算法的基本思想就是讲内存分为俩块,每次只用其中一块 ,当这一块用完,就将还活着的对象复制到另外一块上面,赋值算法不会产生内存碎片 缺点耗空间(需要另一个幸存区) ,如果对象存活率太高,那将会100%复制 并将引用重置 这将非常耗费时间,要是用复制算法必须保证对象存活率很低

标记清除法

老年代采用该GC算法

先标记要回收的对象,然后再统一回收这些对象

优点:不需要另一个幸存区空间 省空间

缺点:俩次扫描 一次标记 一次清除 清除之后 会产生内存碎片,在gc的时候需要停止应用

标记整理

老年代使用该回收算法 老年代一般使用标记清除算法或者标记清除+标记整理混合实现(解决碎片化)

好处是解决了碎片 缺点是移动对象的成本
深入理解JVM虚拟机_第6张图片
看完博客 相信你能做出最后这四道大厂面试题了

你可能感兴趣的:(Java)