30道“热乎乎”的 JVM 典型题目剖析!

写在前面

你们好,我是片头专栏《从零开始带你成为JVM实战高手》的做者,外号救火队队长,目前在阿里任职。java

这个专栏已经写做一周了,也在好友石杉老哥公众号这里宣传霸屏一周了,实在是感谢老哥们儿的大力推荐,有空来杭州必定请你喝两杯^_^web

好了,言归正传,从第一周读者的反响来讲,总体很好,由于定位是从零开始,我用了大量的手绘彩图进行讲解,这点深得你们赞同。windows

不过,也有很多“老鸟”同窗但愿快一些,尽快到达后面的精华部分:案例实战。不过我仍是想提一句,由于照顾到不少JVM基础薄弱甚至没有基础的同窗,因此仍是会稳扎稳打,但愿这些有基础的同窗,权当复习一遍吧!tomcat

另外,第一周的文章,你们的互动也很活跃。看到这些我很是欣慰,若是光是我写,你不思考,那效果会大打折扣。安全

下面,我整理了第一周全部同窗问题中最典型的30个问题,并给出了解答,你们能够仔细看看,认真思考,看是否是你也对这些问题曾经有过疑惑?微信

问题一

问题多线程

方法走完,引用消失,堆内存还未必消失。好多人在作报表导出的时候,就会在for循环里不断的建立对象,很容易形成堆溢出,请问这种大文件导出怎么破?并发

解答 jvm

建议不要在for里建立对象,能够在外面搞一个对象,for循环里对一个对象修改数据便可工具


问题二

问题

1.Java支持多线程,每一个线程有本身的Java虚拟机栈和本地方法栈,是这样吗?

2.新建的实例在堆内存,实例变量也是在堆内存? 是这样吗?

解答

一、2两点均理解正确


问题三

问题

您好,我不太看懂入栈和出栈有什么意义,能够给我解释一下吗?谢谢!

解答

入栈的时候,就是你执行一个方法的时候,为这个方法建立一个栈帧入栈

出栈,就是你的方法执行完毕了,就会出栈,其实这个不用急,明天的文章会有详细的图解,你会看明白的。


问题四

问题

若是是父类子类的状况是下面哪一种呢? 加载父类->加载子类->初始化父类->初始化子类, 加载父类->初始化父类->加载子类->初始化子类

解答

不是的,加载父类就是父类,除非用到子类才会加载子类;可是加载子类要初始化以前,必须先加载父类,初始化父类


问题五

问题

类加载器有三层,若是在第二层的类加载器能够加载这些类的话,就没有必要往上去找他的父类加载吗?

既然说类只有用到的时候才加载到内存中,那么new对象的时候确定用到,可是是否是先经历过类的全部过程才将类实例化?

解答

没错,必须先加载类,再实例化对象


问题六

问题

第一课内容比较详细的讲解了java程序的执行过程,可是感受提出的问题并不能在文章中找到答案,也许是一个课后须要本身找寻答案的提问?仍是但愿能够有一个比较全面的回答的

解答

提出的问题是给你们的思考题,次日会给出简单的解释,可是其实理解了文章的内容,彻底能够本身找资料去理解,这是一个小做业,是一个思考的过程


问题七

问题

Object Header(4字节) + Class Pointer(4字节)+ Fields(看存放类型),可是jvm内存占用是8的倍数,因此结果要向上取整到8的倍数

解答

很好,就是这样


问题八

问题

若是我有一个静态的成员变量int,那我多线程更改是否会有线程安全问题,为何?

解答

静态成员变量,他在内存里,只有一份,就是属于类的。你多个线程并发修改,必定会有并发问题,可能致使数据出错。


问题九

问题

类加载是按需加载,能够一次性加载所有的类吗?

解答

若是是默认的类加载机制,那么是你的代码运行过程当中,遇到什么类加载什么类。若是你要本身加载类,那么须要写本身的类加载器


问题十

问题

为何必需要一级一级类加载器的往上找,直接从顶层类加载器开始找不就好了吗?

解答

其实关于这个问题,不用过于纠结,每一层类加载器对某个类的加载,上推给父类加载器,到顶层类加载器,若是发现本身加载不到,再下推回子类加载器来加载,这样能够保证绝对不会重复加载某个类。

至于为何不直接从顶层类加载器开始找,那是由于类加载器自己就是作的父子关系模型

你想一下Java代码实现,他最底下的子类加载器,只能经过本身引用的父类加载器去找。若是直接找顶层类加载器,不合适的,那么顶层类加载器不就必须硬编码规定了吗?

这就是一个代码设计思想,保证代码的可扩展性。


问题十一

问题

是在执行new replicamanager()这行代码的时候加载replicamanger类吗?仍是说加载cafka的时候就同时加载了呢?

解答

执行new ReplicaManager的时候加载类



问题十二

问题

仍是没有明白 jvm和平时运行在机器上的系统之间是什么关系呢

解答

其实很简单,你运行在机器上的系统,其实就是一个JVM进程,JVM进程会执行你系统里写好的那些代码


问题十三

问题

  1. class文件分配内存是在准备阶段,那类的class对象是在准备阶段建立的吗?
  2. 若是实例变量有初始值,那实例变量是和类变量一同在初始化阶段赋值的吗?
  3. 初始化以后是否是就有实例了

解答

  1. 类是在准备阶段分配内存空间的
  2. 实例变量得在你建立类的实例对象时才会初始化
  3. 类的初始化阶段,仅仅是初始化类而已,跟对象无关,用new关键字才会构造一个对象出来


问题十四

问题

双亲委派能够解决类重复加载的问题。按照文章中介绍每一个类加载器有不一样的类加载路径,这些类加载路径是否可能重叠?

解答

不一样类加载器的路径,通常是不会重叠的


问题十五

问题

自定义的类加载器自己是由系统加载器加载的,也就是说其自己是没有加密的,那么我拿到该类反编译就能够看到若是解密class文件了,请问老师是这样么?

解答

是的,因此说对class文件须要作特殊混淆处理,有商用的产品能够用


问题十六

问题

做为一个web容器,既要解决跨应用公共共享问题也要解决独立应用独立问题。tomcat必须支持多层级的自定义类加载器

解答

很好的推测,明天会给出答案


问题十七

问题

用户使用类的时候应该是但愿类已经准备好了一些数据,我猜测jvm设计者设计先执行static代码块的机制,是但愿开发者在这里把使用类以前须要准备的工做在这里准备好

  1. 为何类的初始化须要执行静态代码块,给静态成员变量赋值,是由于这些数据是在方法区吗?
  2. 启动类、扩展类和自定义加载器都已经指定了加载路径,因此不该该会有重复加载类的问题吧,因此双亲委派是否是没有必要

解答

  1. 没错,必须有初始化过程,准备好类级别的数据
  2. 双亲委派,避免重复加载,评论区里屡次回复了这个问题,能够看一看


问题十八

问题

其实初始化时机就是对类的主动使用:调用静态方法时对类的主动使用的一种场景,main方法本质上是个static方法,没有调用的main方法和没有调用的static方法没区别!

有一个问题,包含main方法的类会优先加载,若是一个项目中有多个类中都有main方法,都会加载么?

解答

不会的,你启动一个jar包,须要指定某个main主类,优先就是加载他


问题十九

问题

tomcat自己是java程序,那么tomcat的实现程序的class是由应用类加载器加载的,用户本身的java程序war包,放入tomcat的程序的classpath中

这样用户的程序和tomcat的程序都是由应用类加载器加载了,也就是处于一个jvm中了

解答

很是好的回复,明天文章会给出答案


问题二十

问题

有一个问题,包含main方法的类会优先加载,若是一个项目中有多个类中都有main方法,都会加载么?

解答

你启动一个jar包的时候,会指定是走哪一个main方法所在的类,是惟一的


问题二十一

问题

  1. 为何类的初始化须要执行静态代码块,给静态成员变量赋值,是由于这些数据是在方法区吗?
  2. 启动类、扩展类和自定义加载器都已经指定了加载路径,因此不该该会有重复加载类的问题吧,因此双亲委派是否是没有必要

解答

  1. 没错,类在方法区,他在内存里,因此你必须给他初始化,赋值
  2. 仍是有必要,好比启动类加载器,能够经过一些方式指定加载其余目录的类,那么你必须得走双亲委派,若是对那些特殊区域的类加载,走双亲委派,才能上推到启动类加载器去执行,不会重复加载


问题二十二

问题

老师好请问类加载双亲委派机制 为何要先找父加载 而不是本身找?这种设计的好处是?

解答

好处就在于,每一个层级的类加载器各司其职,并且不会重复加载一个类。

好比你代码里用两个不一样层级的类加载器,都去尝试加载了某个类,若是有双亲委派机制,那么都会先找父类加载器去加载,若是加载到了,那么之后就只会是他去加载这个类。

不然若是没有双亲委派机制,那么岂不是两个不一样层级的类加载器能够加载同一个类,形成类的重复加载!


问题二十三

问题

自定义类加载器如何实现?

解答

本身写一个类,继承ClassLoader类,重写类加载的方法,而后在代码里面能够用本身的类加载器去针对某个路径下的类加载到内存里来


问题二十四

问题

看到一个词:动态部署,那么是否也有对应的静态部署?如何解释呢?(谢老师回答)

解答

假设一个背景在Tomcat部署系统的话,那么动态部署,也成为热部署

就是直接系统放入Tomcat对应目录,他自动就从新加载你最新的代码给你热部署了,不须要对Tomcat进行停机再重启;

反之,则是先中止Tomcat,而后部署最新代码到Tomcat对应目录里,而后重启Tomcat


问题二十五

问题

-XX:+TraceClassLoading 能够看加载了哪些类,动手实验了一下,jre\lib\rt.jar下的类所有加载了,其余都是用到时候加载。

解答

没错,明天更新的第三篇文章里,会讲解类加载机制,rt.jar这属于核心类库,属于支撑咱们Java系统运行的底层类库,因此他必定会被加载

咱们本身写的代码,通常是你代码运行使用到了哪一个类,就会去加载哪一个类


问题二十六

问题

老师,类加载器是把jar包里的全部类一次性所有加载进去吗?

解答

不是的,首先加载包含main方法的主类,接着是运行你写的代码的时候,遇到你用了什么类,再加载什么类


问题二十七

问题

经过代码混淆机制,加大反编译以后的可读性!或者是否能够基于二进制加密呢,学生没用过!

解答

其实如今对于这个通常都是用商业产品的,有不少第三方公司提供加密产品,能够百度一下,class文件加密,就能够看到,直接用他们的产品便可


问题二十八

问题

Class源文件的保护,能够采用代码混淆技术,方式有不少,如回答区中老师提到的商用加密软件

解答

很是好,就是这样


问题二十九

问题

看文中内容,是会加载两次字节码吗,第一次加载进jvm,而后程序执行的时候再加载。有点不解!

解答

你好,不是加载两次,是JVM先把“.class”字节码文件中的类加载到内存里,而后执行的时候,就直接使用加载好的类极客,不会重复加载


问题三十

问题

class文件经过工具能够反编译的,请问有没有方法对class文件进行加密又不影响它的执行。windows桌面程序里通常都是打包成dll文件,java中有没有比较好的方式?

解答

能够的,好比jvmti小工具就能够实现class文件的加密

另外其实为了保护源代码安全,有不少商业公司推出了专业级别的class加密产品,能够付费使用。

解密的话通常能够基于自定义的类加载器来实现,在加载类的时候把class给解密,这样就能够保护本身的源代码安全了。


最后,附上两张Tomcat类加载若是按委派模型的加载流程和实际实现的流程(专栏读者所画)



这些,就是本周展现的典型问题了。你都理解了吗?

专栏刚更新一周,收获了很多同窗的好评,这是对我写做付出的最好回报。在此继续霸占朋友的公号,给本身打个小广告,厚着脸皮贴出截图,感谢你们支持!


END


推荐一个专栏:

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

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

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

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

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

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

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

相关文章
相关标签/搜索