JVM必懂知识点-java后端面试(自用笔记,更新中)

1. JVM模型

img

字节码文件先通过类装载子系统装载到运行时数据区(内存区域),然后由执行引擎执行字节码文件。

堆:new出来的对象一般都在堆上

栈(线程栈,虚拟机栈):栈是每一个线程独享的,每一个线程都会有一个自己的栈。主要存放线程执行过程中的局部变量,一个方法对应一个栈帧内存区域,栈帧内存区域还包括局部变量表,操作数栈,动态链接,方法出口。

本地方法栈:

方法区:类的字节码文件被类装载子系统装载到方法区,方法区一般存放常量+静态变量+类元信息(类的结构信息,比如类有啥常量,啥方法)

2. 垃圾回收

如何定位垃圾

  • 引用计数法:对对象计数,当引用数量为0时,则是垃圾。缺点:解决不了循环引用(Python用的)

  • 根可达性算法:从gc Root根上开始找,找不到的都是垃圾。

    • 有哪些instance是gc root:线程栈的变量、静态变量、常量池、JNI指针

垃圾回收触发条件

新建对象会优先放到eden区,当eden区满了,则触发Minor GC,通过拷贝算法把活下来的对象从eden复制到s1区,eden区空间回收。下次Minor GC时,eden和s1都要扫描,然后把活下来的对象放到s2,然后把eden和s1清空。当对象很大,eden区放不下时,放到老年代。

纠正:新生代和老年代占用内存默认1:2

Minor GC:eden园满时进行minorGC,然后将Eden区存活的对象放到from区,分代年龄+1,下次eden区满时,再次进行minorGC,将Eden和from区的存活对象放到to区(survive区分为from 和to),分代年龄+1.当分代年龄到达15时,则讲对象

Full GC:老年代满时,进行fullGC,尝试收集整个堆的垃圾对象,无法回收则溢出,否则进行垃圾收集,fullGC过程中会停掉应用线程,也就是Stop The World(minorGC也会STW,但是很快,影响不大),java虚拟机调优的目的就是减少FullGC

常见的垃圾回收算法

  • 标记清除算法(Mark-Sweep):

标记成垃圾以后,直接删除;

优点:简单

缺点:碎片化严重

  • 拷贝算法(Copying):

只能用一半空间,当这一半内存用完后,垃圾收集器进入,将这部分空间的可用部分转移到另一半并整理。

优点:简单

缺点:浪费内存

  • 标记压缩算法(Mark-Compact):

回收的时候顺便做整理空间。

优点:没有碎片化

缺点:效率很低

垃圾回收器

分为两种,一种是gc时必须要stw的,另一种是gc线程和业务线程并发的。

3. JVM调优

定位问题

生产环境下,可以半夜执行,或者dump一份(不能直接dump,可以隔离出一台机器),或者测试环境压测执行。

流程:定位进程,定位线程,看堆栈信息,重复看对象信息,看哪些对象一直不能被回收。

命令

top :实时显示系统中各个进程的资源占用情况。

top -Hp:

jps:显示当前系统的java进程情况及进程id

jinfo:可以用来查看 Java 进程运行的JVM参数

jstack:打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息

jstat:可以查看堆内存各部分的使用量,以及加载类的数量。

jmap:打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其数量)

Arthas

可以替代以上命令。

Dashboard:和top差不多

Headdump:和jmap差不多

thread:把所有线程打印出来,也可以查死锁

jvm:和jinfo差不多

例子:

在垃圾回收过程中,会进行对象动态年龄判断,如果一批对象的总大小大于survivor区域的50%,则直接把这批对象放到老年代,

如图情况,eden区满了之后,活的对象大于survivor区容量的50%,则直接放到老年代,很短时间就会触发FullGC,所以可以加大survivor区域。

JMM内存模型

方法里的变量,在JVM哪个区,对象在哪个区

4. 面试题补充

  • 请解释一下对象的创建过程(半初始化):

    eg : 类T,T t = new T(),构造方法中有个成员变量int m = 8

    Class T{

    int m = 8;

    }

    • 申请一块内存 ,new出一个对象,成员变量此时值为0。

    • 调用构造方法,此时m赋值为8

    • 在变量t和新new出的对象之间建立关联

  • 加问DCL(Double Check Lock)单例和voltail问题(指令重排):

    volitail:线程间可见+禁止重排序

    重排序:cpu的乱序执行,在读等待时,运行没有依赖关系的其他指令。

    • 需要,因为DCL单例会判断instance是否为空,当

  • 对象在内存中的存储布局(对象与数组的存储不同):

    普通对象:

    • markword:对象头8个字节

    • Class pointer:类型指针,标识该对象类型

    • instance data:实例数据,m的位置

    • padding:对齐、空间换时间、读写效率高

    数组:

    • 多一个数组长度

  • 对象头具体包括什么?(锁、gc、hashcode)

    markword:3个内容。锁信息、gc信息(age)、hashcode(最原始的hashcode)

  • 对象怎么定位?(直接间接)

    • 句柄方式/直接指针区别:句柄方式方便gc,gc复制时,t不需要变。

  • 对象怎么分配?(栈上-线程本地-eden-old)

    • 不存在逃逸的小对象(对象只在该方法内存活)可以存放在栈上,此时不存在gc,效率非常高。

    • 如果栈不能分配,判断是不是很大,如果很大,放到老年代。

    • 如果不大,则分配在线程本地缓冲区,如果线程本地缓冲区分配不下,则分配在eden区(为了防止内存冲突,在eden区给每个线程一块内存用于存储自己线程对象,叫做线程本地缓冲区 )。

    • 经历gc、将对象清除

  • 一个Object占用多少字节?

    • markword 8个字节、class pointer (默认压缩:4字节)、padding(4字节)

    • 所以16字节

  • Class对象是在堆中还是方法区?

    • 在方法区堆。o先指向了方法区的c++实现的对象,这个对象的内部指向了堆中的O.class,为了方便反射。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值