ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JVM疑难问题

2022-07-12 20:00:53  阅读:157  来源: 互联网

标签:疑难问题 对象 回收 线程 TLAB JVM GC 内存


数组类创建过程

【结论】数组类本身并不是由类加载器负责创建的,而是由JVM直接在内存中动态构造出来的

理解:
String[] Student[] Integer[] int[]

【结论】数组不是类加载器创建的而是java虚拟机直接创建的,知道这个结论就可以了,因为数组不属于类

165547629342870

核心就是:
创建数组类的过程:
1、如果数组的元素类型是引用类型,那么就遵循定义的加载过程递归加载和创建数组的元素类型。
2、JVM使用指定的元素类型和数组维度来创建新的数组类。
引导类加载器,又叫启动类加载器,就是最核心的类加载器。

复制算法特殊情况

165547804506153
【问题】复制算法这里说S1空间已满就进入老年代,但是不应该是每次GC存活下来的对象年龄加一,当达到一个阀值的时候才进入老年代否则会再次在新生代GC吗
【核心思路】
这个上面说的是一种特殊情况,你理解着就行,面试不需要这么说;jvm内部会有很多优化措施,你理解这个就是一种优化措施就行,这个只是理解
【问题1】
那每次new一个对象是只在eden区中存放吗,还是S0或S1也会有
【答案】
一般情况下都是在eden创建的,只有经过新生代minor gc才会进入s0或s1,不会在so或s1新建
【问题2】
165547829264612
那这里的垃圾对象是指第二次GC时会被清除的对象,对吧?
【答案】
对的,先清除不可达的,然后把eden和s0的都复制到s1,然后so和eden就清空了

类的不同版本相关问题

165547861259638
【问题1】
老师这个有什么示例吗?
【答案】
这个说的是纯理论,你理解就行,实际项目往往要避免的是同一类的不同版本,因为你想,除了写这个类的,后面的接手的不知道这个情况Bug都没法修,这属于不符合开发规范的。这块面试的时候最好别提

System.gc()

【问题1】System.gc()算手动回收对象吗?还有别的方式可以手动回收对象吗?
虚、弱引用算是吗?
【答案】
这个是给垃圾回收进程建议,让垃圾回收进程回收,jvm中没有手动回收的。
你即使设置=null也是让不可达,啥时候回收是垃圾处理进程决定的

虚、弱只是确定回收的优先顺序,这个就是纯理论,知道就行,实践中没人这么用。

jvm中垃圾回收是单独进程,而且垃圾回收的时候用户线程是暂停的,所以jvm中就没有设置手动回收垃圾的机制,要不跟前面的暂停就冲突了,你可以这么简单理解,实际面试有人问也是问结论,这块不会有人深入问的。

栈的OOM相关问题

【问题1】栈OOM是怎么产生的呢?
【答案】
比如有慢代码,导致每个接口要1分钟才能返回,压力一来,又没有设置最大线程池,线程很多,是不是就OOM了

比如递归没写结束条件,就会发生栈溢出

【问题2】如何判断堆OOM的原因是内存溢出还是内存泄露?
【答案】
内存溢出和泄漏表象有可能不一样,一般来说OOm都是溢出,java进程还在但是已经不响应了,内存泄漏可能进程不存在(被操作系统kill掉了),当然,没那么绝对,你现在建议只回答理论和可能是什么原因导致的问题就行。

比如OOM一般是死循环或者创建大量的对象导致的,内存泄漏是该回收的未回收,或者直接内存使用有错误,比如Nio里面异常了等等。

嗯嗯,你重点还是说理论,你的理解,解决可以说个思路就行,具体实践没用过,面试就这么答复,面试官问为什么学自己能说出所以然,比如觉着对工作有用等等就行

构造块与构造方法

165564250664183

【问题】为什么这样括起来就是 构造快 呢?
【答案】这个就是语法定义的,{}定义的,在方法外面的,就叫构造块,每次执行构造方法前先执行构造块

内部局部变量

165564258331261
【问题】如果不加int,是不是就 赋值 了
【答案】 回答正确

GCRoot相关的理解

165564264410405

【说明】

  1. 是根据可达性算法判断的,只要不可达就会回收;栈是线程私有的,线程结束栈就会销毁,这个时候栈引用做未GcRoot的对象都不可达了;
  2. 静态变量引用的一般都可达,方法区的方法一般也都不会销毁,但是出现full Gc了就会销毁,这回对象都会被垃圾回收了;

【问题】那作为GcRoot的对象就一直不会被回收吗?
【答案】
所以GC根对象被回收的时间点:栈里面的,线程执行完成,栈销毁了这GCroot对象就回收了;静态变量做GCroot的时候,只有fullgc的时候方法区被gc,这个时候才会被回收,为什么静态变量设计是类中独一份的,存活周期很长

引用传递和值传递相关的

165564292306022

【核心】
引用传递子方法赋值=
图中,标为绿色的地方,这里是v=val是重新指向一块引用地址,前面的value v 的地址块无关

堆中有线程私有的分配缓冲区,这部分是用来装什么的?其他线程可以访问吗?

【核心】
有,你可以理解这部分就是放一些对象,装自己线程独有的对象,其它线程不可以访问的

你理解这个概念就行

就是对象是在eden中,但是是我自己线程私有的一些对象

【完整解释】
这其实是JVM的优化,知道相应的概念即可
本地线程分配缓冲——TLAB
TLAB是虚拟机在堆内存的划分出来的一块专用空间,是线程专属的。在TLAB启动的情况下,在线程初始化时,虚拟机会为每个线程分配一块TLAB空间,只给当前线程使用,这样每个线程都单独拥有一个空间,如果需要分配内存,就在自己的空间上分配,这样就不存在竞争的情况,可以大大提升分配效率。

ps:这里说线程独享的堆内存,只是在“内存分配”这个动作上是线程独享的,至于在读取、垃圾回收等动作上都是线程共享的。即是指其他线程可以在这个区域读取、操作数据,但是无法在这个区域中分配内存。

TLAB 生命周期
在分代收集的垃圾回收器中,TLAB是在eden区分配的。TLAB 是从堆上 Eden 区的分配的一块线程本地私有内存。线程初始化的时候,如果 JVM 启用了 TLAB(默认是启用的, 可以通过 -XX:-UseTLAB 关闭),则会创建并初始化 TLAB。同时,在 GC 扫描对象发生之后,线程第一次尝试分配对象的时候,也会创建并初始化 TLAB。
在 TLAB 已经满了或者接近于满了的时候,TLAB 可能会被释放回 Eden。GC 扫描对象发生时,TLAB 会被释放回 Eden。TLAB 的生命周期期望只存在于一个 GC 扫描周期内。在 JVM 中,一个 GC 扫描周期,就是一个epoch。那么,可以知道,TLAB 内分配内存一定是线性分配的。

String.inern在JDK1.7前后的变化

String.intern在jdk1.7之后就是往常量池放的东西变了:原来在常量池中找不到时,复制一个副本放到常量池,1.7后则是将在堆上的地址引用复制到常量池。
如下图:

165564377308537

jdk7之后如下图:

165564424897611

标签:疑难问题,对象,回收,线程,TLAB,JVM,GC,内存
来源: https://www.cnblogs.com/faetbwac/p/16471467.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有