公众号后台回复“学习”,获取作者独家秘制精品资料
多年好友心血力作,阿里资深技术专家十余年JVM生产实践经验
《从零开始带你成为JVM实战高手》
限时优惠:88元(正在进行ing)
专栏目录参见文末
扫下方海报进行试读
通过我的海报购买,再返你24元
领取方式:加微信号:Giotto1245,暗号:返现
写在前面
大家好,我是片头专栏《从零开始带你成为JVM实战高手》的作者,外号救火队队长,目前在阿里任职。
这个专栏已经写作一周了,也在好友石杉老哥公众号这里宣传霸屏一周了,在此感谢老哥们儿的大力推荐,有空来杭州一定请你喝两杯^_^
好了,言归正传,从第一周读者的反响来说,整体很好,因为定位是从零开始,我用了大量的手绘彩图进行讲解,这点深得大家赞同。
不过,也有不少“老鸟”同学希望快一些,尽快到达后面的精华部分:案例实战。不过我还是想提一句,因为照顾到很多JVM基础薄弱甚至没有基础的同学,所以还是会稳扎稳打,希望这些有基础的同学,权当复习一遍吧!
另外,第一周的文章,大家的互动也很活跃。看到这些我非常欣慰,如果光是我写,你不思考,那效果会大打折扣。
下面,我整理了第一周所有同学问题中最典型的30个问题,并给出了解答,大家可以仔细看看,认真思考,看是不是你也对这些问题曾经有过疑惑?
问题一
建议不要在for里创建对象,可以在外面搞一个对象,for循环里对一个对象修改数据即可
问题二
2.新建的实例在堆内存,实例变量也是在堆内存? 是这样吗?
解答1、2两点均理解正确
问题三
入栈的时候,就是你执行一个方法的时候,为这个方法创建一个栈帧入栈
出栈,就是你的方法执行完毕了,就会出栈,其实这个不用急,明天的文章会有详细的图解,你会看明白的。
问题四
不是的,加载父类就是父类,除非用到子类才会加载子类;但是加载子类要初始化之前,必须先加载父类,初始化父类
问题五
类加载器有三层,如果在第二层的类加载器可以加载这些类的话,就没有必要往上去找他的父类加载吗?
既然说类只有用到的时候才加载到内存中,那么new对象的时候肯定用到,但是是不是先经历过类的所有过程才将类实例化?
解答没错,必须先加载类,再实例化对象
问题六
问题 第一课内容比较详细的讲解了java程序的执行过程,但是感觉提出的问题并不能在文章中找到答案,也许是一个课后需要自己找寻答案的提问?还是希望可以有一个比较全面的回答的 解答
提出的问题是给大家的思考题,第二天会给出简单的解释,但是其实理解了文章的内容,完全可以自己找资料去理解,这是一个小作业,是一个思考的过程
问题七
问题 Object Header(4字节) + Class Pointer(4字节)+ Fields(看存放类型),但是jvm内存占用是8的倍数,所以结果要向上取整到8的倍数 解答
很好,就是这样
问题八
静态成员变量,他在内存里,只有一份,就是属于类的。你多个线程并发修改,一定会有并发问题,可能导致数据出错。
问题九
如果是默认的类加载机制,那么是你的代码运行过程中,遇到什么类加载什么类。如果你要自己加载类,那么需要写自己的类加载器
问题十
其实关于这个问题,不用过于纠结,每一层类加载器对某个类的加载,上推给父类加载器,到顶层类加载器,如果发现自己加载不到,再下推回子类加载器来加载,这样可以保证绝对不会重复加载某个类。
至于为什么不直接从顶层类加载器开始找,那是因为类加载器本身就是做的父子关系模型
你想一下Java代码实现,他最底下的子类加载器,只能通过自己引用的父类加载器去找。如果直接找顶层类加载器,不合适的,那么顶层类加载器不就必须硬编码规定了吗?
这就是一个代码设计思想,保证代码的可扩展性。
问题十一
执行new ReplicaManager的时候加载类
问题十二
其实很简单,你运行在机器上的系统,其实就是一个JVM进程,JVM进程会执行你系统里写好的那些代码
问题十三
class文件分配内存是在准备阶段,那类的class对象是在准备阶段创建的吗?
如果实例变量有初始值,那实例变量是和类变量一同在初始化阶段赋值的吗?
初始化之后是不是就有实例了
类是在准备阶段分配内存空间的
实例变量得在你创建类的实例对象时才会初始化
类的初始化阶段,仅仅是初始化类而已,跟对象无关,用new关键字才会构造一个对象出来
问题十四
不同类加载器的路径,一般是不会重叠的
问题十五
是的,所以说对class文件需要做 特殊混淆处理 ,有商用的产品可以用
问题十六
很好的推测,明天会给出答案
问题十七
用户使用类的时候应该是希望类已经准备好了一些数据,我猜想jvm设计者设计先执行static代码块的机制,是希望开发者在这里把使用类之前需要准备的工作在这里准备好
为什么类的初始化需要执行静态代码块,给静态成员变量赋值,是因为这些数据是在方法区吗?
启动类、扩展类和自定义加载器都已经指定了加载路径,所以不应该会有重复加载类的问题吧,所以双亲委派是不是没有必要
没错,必须有初始化过程,准备好类级别的数据
双亲委派,避免重复加载,评论区里多次回复了这个问题,可以看一看
问题十八
其实初始化时机就是对类的主动使用:调用静态方法时对类的主动使用的一种场景,main方法本质上是个static方法,没有调用的main方法和没有调用的static方法没区别!
有一个问题,包含main方法的类会优先加载,如果一个项目中有多个类中都有main方法,都会加载么?
解答不会的,你启动一个jar包,需要指定某个main主类,优先就是加载他
问题十九
tomcat本身是java程序,那么tomcat的实现程序的class是由应用类加载器加载的,用户自己的java程序war包,放入tomcat的程序的classpath中
这样用户的程序和tomcat的程序都是由应用类加载器加载了,也就是处于一个jvm中了
解答非常好的回复,明天文章会给出答案
问题二十
你启动一个jar包的时候,会指定是走哪个main方法所在的类,是唯一的
问题二十一
为什么类的初始化需要执行静态代码块,给静态成员变量赋值,是因为这些数据是在方法区吗?
启动类、扩展类和自定义加载器都已经指定了加载路径,所以不应该会有重复加载类的问题吧,所以双亲委派是不是没有必要
没错,类在方法区,他在内存里,所以你必须给他初始化,赋值
还是有必要,比如启动类加载器,可以通过一些方式指定加载其他目录的类,那么你必须得走双亲委派,如果对那些特殊区域的类加载,走双亲委派,才能上推到启动类加载器去执行,不会重复加载
问题二十二
好处就在于,每个层级的类加载器各司其职,而且不会重复加载一个类。
比如你代码里用两个不同层级的类加载器,都去尝试加载了某个类,如果有双亲委派机制,那么都会先找父类加载器去加载,如果加载到了,那么以后就只会是他去加载这个类。
否则如果没有双亲委派机制,那么岂不是两个不同层级的类加载器可以加载同一个类,造成类的重复加载!
问题二十三
自己写一个类,继承ClassLoader类,重写类加载的方法,然后在代码里面可以用自己的类加载器去针对某个路径下的类加载到内存里来
问题二十四
假设一个背景在Tomcat部署系统的话,那么动态部署,也成为热部署
就是直接系统放入Tomcat对应目录,他自动就重新加载你最新的代码给你热部署了,不需要对Tomcat进行停机再重启;
反之,则是先停止Tomcat,然后部署最新代码到Tomcat对应目录里,然后重启Tomcat
问题二十五
没错,明天更新的第三篇文章里,会讲解类加载机制,rt.jar这属于核心类库,属于支撑我们Java系统运行的底层类库,所以他一定会被加载
我们自己写的代码,一般是你代码运行使用到了哪个类,就会去加载哪个类
问题二十六
不是的,首先加载包含main方法的主类,接着是运行你写的代码的时候,遇到你用了什么类,再加载什么类
二十七
其实现在对于这个一般都是用商业产品的,有很多第三方公司提供加密产品,可以百度一下,class文件加密,就可以看到,直接用他们的产品即可
问题二十八
非常好,就是这样
问题二十九
你好,不是加载两次,是JVM先把“.class”字节码文件中的类加载到内存里,然后执行的时候,就直接使用加载好的类即可,不会重复加载
问题三十
可以的,比如jvmti小工具就可以实现class文件的加密
另外其实为了保护源代码安全,有很多商业公司推出了专业级别的class加密产品,可以付费使用。
解密的话一般可以基于自定义的类加载器来实现,在加载类的时候把class给解密,这样就可以保护自己的源代码安全了。
最后,附上两张Tomcat类加载如果按委派模型的加载流程和实际实现的流程(专栏读者所画)
这些,就是本周展示的典型问题了。你都理解了吗?
专栏刚更新一周,收获了不少同学的好评,这是对我写作的最大肯定。在此继续霸占朋友的公号,给自己打个小广告,厚着脸皮贴出截图,感谢大家支持!
END
如有收获,请划至底部,点击“在看”,谢谢!
《从零开始带你成为JVM实战高手》
专栏详细目录
欢迎长按下图关注公众号石杉的架构笔记,后台回复“学习”
获取作者独家秘制精品资料
BAT架构经验倾囊相授