【进阶JVM高手之路】32个Java虚拟机知识点快速梳理!

本文来源:《从零开始带你成为JVM实战高手》java

第二周答疑汇总web

============================spring

你们好,我是救火队队长。不知不觉,《JVM实战高手》专栏已经开始两周了,每篇文章,你们都有各类各样的问题。数据库

在解答这些问题的过程当中,我也时不时会受到新的启发,就是这个技术点,我或许应该这么讲,你们能听得更加明白一些。tomcat

经过对你们的答疑,反过来让我继续打磨文章,这事儿还挺有意义微信

下面将你们上周提出的问题,作了一个小汇总:网络

问题
并发

既然栈帧存放了方法对应的局部变量的数据,也包括了方法执行的其它相关信息。jvm

那为何不把程序计算器那块记录执行的状况,也放在各个方法本身的栈帧里,而是要单独列一个程序计数区去存储呢?jsp

答:这就是JVM设计者的设计思想了,由于程序计数器针对的是代码指令的执行,Java虚拟栈针对的是放方法的数据,一个是指令,一个是数据,分开设计

问题

思考题回答:什么状况下一个类会被回收?

  • 首先该类的全部实例(堆中)都已经被回收;

  • 其次该类的ClassLoader已经被回收;

  • 最后,对该类对应的Class对象没有任何引用。知足上面三个条件就能够回收该类了。

答:正解

问题

方法执行完后, 栈帧立马被出栈, 那该栈帧中的变量等数据是立马就被回收掉吗?仍是须要等垃圾回收线程扫描到再回收掉?

答:出栈就没了

问题

若是把public static int flushInterval = Configuration.getInt("xxx");中的static去掉, 那后面的getInt是在何时执行的呢 ?

我本身测试了一下,好像是在构造方法以前执行的, 不明白这个到底属于什么阶段?

答:这是属于类的对象实例初始化的阶段

问题

双亲委派模型设计的出发点很重要,文章漏了。对于任意一个类,都须要由加载它的类加载器和这个类自己一同确立其在Java虚拟机中的惟一性,每个类加载器,都拥有一个独立的类名称空间。

也就是说,判断2个类是否“相等”,只有在这2个类是由同一个类加载器加载的前提下才有意义

不然即便这2个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不一样,这2个类一定不相等。

基于双亲委派模型设计,那么Java中基础的类,Object相似Object类重复屡次的问题就不会存在了

由于通过层层传递,加载请求最终都会被Bootstrap ClassLoader所响应。加载的Object类也会只有一个

不然若是用户本身编写了一个java.lang.Object类,并把它放到了ClassPath中,会出现不少个Object类,这样Java类型体系中最最基础的行为都没法保证,应用程序也将一片混乱

答:这位同窗很是不错,对jvm有必定的研究,不过咱们第一周的文章,并非说漏掉你说的这些点,而是咱们的写做思路,是按部就班,这点很重要。

若是在刚开始就给出大段这种说明,那么只有少数人会看懂,回到普通的那种学院派纯理论的知识传递方法了。

你说的很好,不过但愿耐心跟着继续看,咱们会有意把不少细节放在后面讲,按部就班,保证不少小白同窗都轻松学习,这点很重要。

问题

tomcat须要破坏双亲委派模型的缘由:

  1. tomcat中的须要支持不一样web应用依赖同一个第三方类库的不一样版本,jar类库须要保证相互隔离;

  2. 同一个第三方类库的相同版本在不一样web应用能够共享

  3. tomcat自身依赖的类库须要与应用依赖的类库隔离 (3)jsp须要支持修改后不用重启tomcat便可生效 为了上面类加载隔离和类更新不用重启,定制开发各类的类加载器

答:回答的很是好

问题

老师您好,我想问一下,咱们的应用若是关掉,建立在堆中的对象,还有方法区的数据都还在吗?

答:应用关了,那么系统对应的JVM进程就没了,那JVM内存区域的数据就全没了

问题

请问老师:

  1. “实例对象都已经从Java堆内存里被回收”和“Class对象没有任何引用”是一个概念么?

  2. “ClassLoader已经被回收”,何时会回收?

答:

  1. 不是,Class对象表明类,若是你有变量引用了类的Class对象,那么就是有引用

  2. 好比你自定义的ClassLoader,自己就是个对象,一旦他没人再使用了,就会被垃圾回收

问题:引用Class对象的是该类的实例对象?仍是其余什么?

答:好比用反射,能够获取一个对象的类的Class对象实例,好比Class clazz = replicaManager.getClass(),就能够经过replicaManager引用的对象,获取到ReplicaManager类的Class对象,那个clazz变量,就能够引用这个Class对象

问题

第二周打卡,跟上节奏。回答今日思考题:项目中托管给Spring管理的对象,带@Configration的配置对象,都是长期存在老年代。

本身定义那些pojo对象,若是不被定义为类对象就是朝生夕灭的,因此分配在年轻代里面。

答:很是好

问题

public void load(){ A a = new A(); a这个保存地址的变量是存在虚拟机栈的,这个方法执行完成后就销毁了,

那new A()这个对象是须要等待垃圾回收线程扫描后才回收吗?

仍是和a这个变量同时回收?

答:对象要等待垃圾回收才销毁

问题

gc回收的是软引用,弱应用和虚引用,关于软引用和弱引用傻傻分不清,这二者有何异同,请指教


答:内存不够才会回收软引用对象,内存空间足够的话,不会回收软引用对象。弱引用无论内存空间够不够,只能撑到下次垃圾回收以前,就被会回收。

问题

思考题回答:目前的系统,大部分是spring容器的对象,spring默认单实例方式加载,这些对象可能会存在老年代中。

可是方法内部new出来的对象不会存活太长时间,方法结束,引用消息,对象也会在下一次gc被回收。

答:很是好

问题

类初始化时,变量引用的是new出来的对象,此时变量引用的对象会被实例化到堆内存吗?

答:会实例化放到堆内存

问题

老师好。我今天使用Java VisualVm看了一下,发现了一个问题,我配置的是-Xms4M -Xmx4M -Xmn2M。应该是年轻代2M 老年代2M。

写了一个while循环不断的在方法里建立临时变量对象,可是我发现当内存堆达到3m左右的时候,就发生了Minor GC,堆内存回到了2M,而不是4M的时候

理论上不该该是堆内存满了再Minor GC吗?

答:这个很正常的,由于后续第三周会讲新生代的内存结构,其实不是新生代所有占满才minor gc,是里面一块主要的内存区域满了,就minor gc

问题

打卡。作项目时候没有关注系统压力,主要是考虑功能怎么现实,而后按时交付测试。之后能够按老师今天这个思路去估算一下系统压力了。

答:是的,若是没合理估算内存压力,没合理设置jvm内存大小,那么上线以后,可能会发现频繁gc问题,致使系统卡顿,这是jvm优化的第一步,合理估算业务压力,合理设置内存大小

问题

案例总结:

1. 分析系统压力点在哪里?

2. 压力点的每秒请求数?

3. 每一个请求耗时?

4. 每一个请求消耗的内存?

5. 整个系统的全部请求重复1-4。

6. 算出部署多少台机器?每一个机器多少内存?

思考题做答: 平时工做中不多这样预估系统压力,通常个人作法都是部署上去后分配一个堆内存,而后测试时再去监控GC的频率作适当调整。

这样作确实很被动,不少时候上线后发现和测试的GC频率差太多,之后试试老师这种估算方法。

答:很是好

问题

上次发生内存溢出,咱们搞到凌晨5点多,最后咱们老大调大了堆内存解决的,说是因为使用过多的静态内部类,有地方引用到没法释放致使的,不过我如今尚未明白为啥?

答:学完这个专栏,你也能掌握这种能力

问题

这篇文字最重要的收获是分析处理问题的思路,分解而后一步一步分析处理。赞。


答:是的,思路很是的重要,按照这个思路来,大家本身也能作jvm内存压力预估,系统上线前,合理设置一个内存大小

问题

是否是不该该在高峰期的时候让系统进行垃圾回收,这样会形成STW。老师大家线上系统会考虑在低峰期手动触发垃圾回收么?

答:建议不要手动触发,依托合理的内存设置以及参数优化,让系统自行运转

问题

是否是应该经过老师说的估算方式,尽可能设大新生代 ,让系统在高峰期不产生gc?

答:是的,尽可能是这样

问题

老师,那无论三七二十一,在内存大的条件下,多分配给新生代就行了,若是不行就加内存?

答:那你就浪费机器资源,要合理评估,不须要大内存,就用小内存就能够了

问题

一、支付系统高分期须要处理的请求是是否是应该这么算:

100万 / (24 * 3600) ≈ 12,根据28法则,大部分请求发生在中午12点到13点以及晚上的18点到19点

因此 80万请求 / (2 * 3600) ≈ 111,即算出若是单台每秒大概是100多个请求

二、还有就是在完整的支付系统内存占用须要进行预估中,你提到“能够把以前的计算结果扩大10倍~20倍。

也就是说,每秒除了内存里建立的支付订单对象还建立数十种对象” 这里若是要计算的话以前的计算结果是 30 * 500字节 * 20倍 = 300000字节=300KB 是这么算吗?

答:没错的,这是大体估算的方法

问题

老师 您这儿的案例中提到,一个支付请求须要1s中,30个请求也是1s钟,那是否是能够理解为开了30个线程同时并发处理支付请求入库?


答:就是这个意思

问题

文章中写的:

“可能你每秒过来的1000笔交易,再也不是1秒就能够处理完毕了,由于压力骤增,会致使你的系统性能降低,可能偶尔会出现每一个请求处理完毕须要几秒钟”

老师,这里说的压力骤增是磁盘读写压力吗仍是内存CPU压力,出行每一个请求处理完毕须要几秒这里是写入压力吗?与网络有关吗?谢谢

答:都有可能,主要是CPU负载太高,会致使高并发下每一个请求的处理性能直线降低,还有网络问题也会有

问题

咱们订单一天二百多万,线上正常每秒产生也应该在1M以上,xmn2048,xmx8192,原本半个多小时一次minor gc

扩大一百倍,不到一分钟一次,应该会出现案例中的问题,老年代会频繁gc,不过咱们有6g老年代,达到full gc应该时间会稍微长点

答:本身分析的很是好,掌握这个方法了

问题

老师, 能够说下, 为何并发上来了, 压力就会剧增嘛? 哪些方面的压力.

答:并发上来以后,内存、网络带宽、磁盘IO、数据库,都是系统的瓶颈,好比网络带宽打满,你的请求就会排队卡住,磁盘IO变满,数据库性能降低,都会致使请求处理慢几十倍

问题

您好,我有一个问题,就是main函数中建立了对象,这个对象在堆中开启空间,那么若是这个对象中有成员变量,这个成员变量是存在哪里?成员变量的引用存在哪里

答:成员变量也是在堆内存里的

问题

老师我上网查了一下资料,把问题弄明白了。Test.class是被加载了,可是并无 执行初始化步骤。

课程中提到了类加载的时机,可是没有提到类初始化的时机,我把一直理解类的 加载->验证->准备->解析->初始化是一个连续的动做,觉得类一旦加载一定 会当即初始化。

补充类初始化的时机以下:

  1. 当建立某个类的新实例时(如经过new或者反射,克隆,反序列化等)

  2. 当调用某个类的静态方法时

  3. 当使用某个类或接口的静态字段时

  4. 调用Java API中的某些反射方法时,好比类Class中的方法,或者java.lang.reflect中的类的方法时

  5. 当初始化某个子类时

  6. 当虚拟机启动某个被标明为启动类的类(即包含main方法的那个类) 因此System.ou.println(Test.class)不知足上面6种状况,也就没有作初始化

答:对的,就是这样

问题

老师 假如Kafka类里面 声明一个实例变量 private ReplicaFetcher = new ... 这个实例变量放在哪一个区

答:实例变量就在堆内存里

问题

老师 根据示例代码, 我作了如下jvm参数配置:-Xms10m -Xmx10m, 而后在visualVM里跟踪堆栈使用状况。

十分诧异的现象是:在while true循环中,也就是执行fetchFromRemote的时候, 新生代大小一直在有规律的增加,而后不停的minor GC, 每次GC(而不是等到15次之后),老年代都会相应的增加一点。

个人问题是,使新生代增加的究竟是什么对象?GC时又是什么对象跑到老年代里去了?

按个人理解,fetcher对象应该有且只有一份实例,并且while循环中,不会生成新的对象,

最初,新生代里有一份fetcher,而后第16次minor GC的时候,fetcher被转移到老年代, 不管如何,新生代和老年代都不会不断增加。

因此,是否是有什么我不知道的对象混了进去,致使新生代不断增加?

答:新生代到老年代转移的机制不仅是年龄一种,还有别的,下周会详细说明

问题

老师,每一个订单处理时间是1秒和10秒,10秒的就要比1秒的要多加内存吗?请问是怎样的逻辑?可否量化?

答:那你得计算一下,你的内存每秒被使用的速度,根据这个来规划内存大小

还有你要是10秒一个请求,可能内存里累计起来会有大量对象无法释放,会致使瞬间新生代被打满

并且大量对象无法回收,而后所有去老年代,而后老年代也很快就满了,最后内存不够,很快就内存溢出了

END

推荐一个专栏:

《从零开始带你成为JVM实战高手》

做者是我多年好友,之前团队的左膀右臂

一块儿经历过各类大型复杂系统上线的血雨腥风

现任阿里资深技术专家,对JVM有丰富的生产实践经验

专栏目录参见文末,能够扫下方海报进行试读

经过上面海报购买,再返你24元

领取方式:加微信号:Giotto1245,暗号:返现

相关文章
相关标签/搜索