java内存初探(一)

讲道理,这个java虚拟机我感觉自己学的超级差劲,但是呢,面试又重点考察这个,所以手写一次加深印象吧。

一、区域划分
主要划分为堆(包括方法区),栈,本地方法栈,程序计数器

二、java程序的具体执行过程
我们写出来的程序文件后缀都是.java,比如我论文的项目后缀就全都是.java,具体的名称叫做java源码文件。如下图所示:

在这里插入图片描述
源码文件是无法被java虚拟机识别的,所以必须要用java compiler(java编译器)编译成字节码文件(.class),这.class实际上是二进制的数据,但是为什么叫字节码文件呢?我搜了一下,字节码文件长这样。
在这里插入图片描述
行吧,两个16进制放一起就是一个子节,好像还有计算机组成原理方面的知识,说是计算机能够处理的最小内存单位是子节,哦,反正我计算机组成原理没学好,你说啥就是啥。继续继续!!

现在的.class文件就可以被java虚拟机识别了(必须经过java虚拟机处理之后才能成为机器码被硬件识别),不过第一步是用类加载器将.class文件先读入内存中,而不是直接在内存中处,那我就明白了,原来刚才的java compiler是先读取了.java文件,将它处理成.class文件后放回了硬盘的某处,这中间涉及了两次io操作,我记得我用idea的时候,每次运行都会出现target文件夹,应该就是存放.class文件的地方,然后点clean就没了,下次再次运行的时候就会再次编译,这好麻烦啊,写到这里,我又来一个新问题了,如果我不点clean但是改动了.java文件,那么它下次再运行的时候是会运行原来已经编译好的.class文件呢,还是再次编译呢?我觉着java虚拟机不会那么聪明知道我有没有改动,所以它应该是每次运行都重新编译,这可真麻烦啊,吐槽结束,继续继续!

.class读入内存中总得有个地方放它呀,java虚拟机给它弄了个方法区给它呆着,深入理解jvm这本书说方法区是各个线程共享的区域,既然是各个线程共享,那我觉着静态方法静态变量和常量肯定在里面,一查果然在哈哈,当然里面还放了类的信息(类名,方法信息,字段信息(简单来说就是变量?包括了这个变量的名字,类型和修饰符(public、protected和private))),这些东西似乎不太需要垃圾回收吧?所以有人喜欢把它叫做永久代,嗯,古人诚不欺我。

然后再谈谈刚才说到的类加载器(classloader),我原本以为它只有一个,结果后来人家说有三个,分别是bootstraploader extclassloader 和appclassloader
bootstrap class加载器是用c++语言写的,java虚拟机一启动这玩意就初始化了,是最核心的加载器,它可以加载%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。我来查查这些玩意下面都是个啥在这里插入图片描述
在这里插入图片描述
可以看到有sql包,lang包,io包和math包,这些都是我们很熟悉的东西,嗯,不愧是核心包。

extension classloader是扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。还可以加载-D java.ext.dirs选项指定的目录。这个我也来查查是个啥吧在这里插入图片描述
哦,不认识,那就这样吧。

第三个加载器是appclassloader 这玩意也称为systemappclass,用来加载当前应用的classpath的所有类。也就是说我们自己写的类基本上都是由这玩意加载的。

这地位一看就是bootstraploader老大,extclassloader老二appclassloader老三啊,然后上网一查,appclassloader的父加载器是extclassloader,而extclassloader的父加载器是空,这不对啊,明明人家说extclassloader的爹是bootstraploader!再仔细一看,bootstraploader是由c++写的,我们是高贵的c++,你还想让我当你低贱的java中的一员?你整个java的类加载器都是我生的!!!
那行吧,那串一下就是,bootstraploader 生成了extclassloader,extclassloader生成了appclassloader

然后类加载也是有讲究的,一个类加载器查找class和resource时,是通过委托模式进行的,它首先判断这个class类是否已经加载成功,如果没有,那么它自己先不干活,而是让他爹去进行查找,这妥妥的啃老族好吧,那最老的那个是谁?高贵的c++写的bootstraploader啊!我觉着它心里肯定很苦,凭啥我没爹?那没爹坑只能自己干呗,如果它找到了,那么就直接返回,如果没找到,再让它儿子去找,直到回到最开始啃老的那个儿子去查找这些对象,这种机制就叫做双亲委托,这里我又得吐槽一波了,双亲明明是爸妈好吧,你这叫爹爷委托!!!
那为啥写jvm的那群人要助长这种啃老之风呢?我去网上扒了一下:

采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。
原来是这样,行吧,你说的对,我继续。

classloader会将编译阶段的.class文件加载到jvm内存中去,这个阶段会经过装载,连接和初始化的过程。

我写累了,要休息了,晚上再写接下来的嘻嘻。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值