JAVA学习 JVM

一,Java的语言特点:
Java是兼顾编译和解释型的编程语言。
编译体现在运行时JVM会把代码编译成字节码文件,解释体现在JVM会把字节码文件转化成机器能读懂的指令一行一行的执行。

编译型编程语言:把代码直接编译成机器可以读懂的指令,编译不通过则代码无法运行。例如:C语言
解释型编程语言:读一行,执行一行,没有读到错误代码,程序就可以接着运行。例如:Python、JavaScript

Java是静态强类型的编程语言。
静态类型指的是变量的类型在编译时确定,在运行时不可以修改。强类型指的是数据类型不强转,就永远是一个类型。JAVA的对象以及数据类型间的强制转换,对于数据类型的强制转换,范围大的不可以转换成范围小的数据类型,避免数据丢失。

二,JVM和JVM编译器:
JVM将Java代码转换成JVM可以读的字节码文件,再转换成机器可以读的指令,JVM作为中间层,屏蔽掉不同的操作系统的硬件差异(CPU),在不同的操作系统上安装不同版本的JVM, Java就实现了跨平台。加一层要么屏蔽复杂,要么屏蔽差异。

JavaC编译器:源代码->字节码
GIT编译器:常用字节码->机器指令
AOT编译器:源代码->机器指令。

三,计算对象在堆内存占多少个字节:
1、对象头:包含属性的符号引用、对象的年龄、锁信息,指向方法区的内存地址,8个字节。
如果是数组对象,对象头还包含数组的长度,数组的长度也是int值,就再加上4个字节。
2、实例数据:属性的值占4个字节,引用对象的内存地址占4个字节,没有属性可以是0个字节,有属性就有初始化值。
如果是数组对象,数组对象里的实例数据,一个数据占1个字节。
3、padding: JVM要求Java对象的内存大小应是8个字节的倍数,不够,就自动补齐到8的倍数。
4、String是一个数组对象,里面的每一个字符并不是占一个字节,里面是一个char数组的引用。
如何打印一个对象占内存大小:ObjectSizeCalculator. getObjectSize()

四,类的加载过程:
一个类编译以后会形成Java的字节码文件,JVM在使用类时把类的字节码文件加载到方法区。
使用类指的是:创建类的实例、new一个类的实例时,创建子类对象会把继承链上的父类也加载到内存当中,创建内部类的实例也会把外部类加载到内存当中。调用静态方法或静态属性,所属的类也会被加载到方法区,main所属的类会被最先调用,main方法最先入栈。 Java的反射机制也会触发类的加载。

1.类的加载:通过类全限定名获取类的字节码文件,加载到方法区,生成一个class类型的对象。
2.验证:验证class文件是Java类的文件,而不是叫.class的其他伪造的文件。文件格式的验证:Java的字节码文件应以魔术值cafebaby开头。Java的版本号是在虚拟机处理的范围内。
也就是不同版本的Java的开发工具与Java的运行环境JDK中的JVM相适应。高版本的JDK中可以运行低版本的Java开发工具中的代码。
3.准备:为静态变量在方法区中分配内存、并设置初始化值,如果没有初始化值就是默认值0。
public final static int NUM;
可调用不可修改,又没有初始化值,会报错。
4.解析:虚拟机将常量池内的符号引用替换为直接引用的过程,动态分派也是解析的过程。
5.初始化:在类加载到内存中以后,静态变量会放到静态代码块中执行一次。static{};

五、new一个对象的过程中发生了什么?
1.确认类元信息是否存在,确认类有没有加载到方法区。类元信息:描述类的信息。
2.分配对象内存,计算对象的内存大小,先在堆中分配空间,然后在内存中分配空间。
3.设定默认值,不同数据类型,基础类型和引用类型的默认值。
4.设定对象头,设定类的基本信息。
5.执行init方法,调用类的构造器,初始化成员变量,并给类的成员变量赋值,执行实例代码块,并把堆内对象的首地址赋给引用变量。

双亲委派机制:构造器中传入Classloader
Bootstrap Classloader 加载lib目录下的jar包
Extension Classloader 加载lib/est目录下的jar包
Application Classloader 加载classpath类路径下的.class文件
User Classloader

六、类加载器源码阅读:
类加载器是一个类ClassLoader,作用/功能是通过类的全限定名把out目录下、编译后的类的字节码文件加载到内存区。类编译后输出的目录可以修改,在project compiler output中修改。
这几个加载器没有父子关系,而是递归调用findClass()。

七,运行时数据区:
如果计算机只有一个内核那么用户态内核和系统内核互相切换来展现多个程序同时运行。一个进程就是一个软件,一个进程中有多个线程,也就是不同的方法在同时运行。

方法区和堆、线程共有。
堆中不同的实例对象、可以调用方法区的同一个方法,同一个方法可以加入不同的栈中,独立执行。不同的栈之间可以是指向堆中的同一个实例对象。方法一个一个入栈,按照先进后出的顺序,一个一个地执行。

虚拟机栈、本地方法栈、程序计数器线程私有。
(1)虚拟机栈
每一个方法栈桢中包含:
a局部变量表slot槽;
b操作数栈:(i+j)把i压到栈顶、再把j压到栈顶,把j和i弹出来,加法器相加以后,把结果压到栈顶返回到要调用的变量中。
(++i):先自增,再把自增以后的值压到栈顶。
(i++):先把i压到栈顶、然后局部变量表中的i再自增。
c动态链接:程序运行的过程中的符号引用转化成内存地址链上方法。
d方法返回地址:正常退出,执行到return、ireturn、areturn退出。异常退出。

(2)本地方法栈
调用本地方法时创建的栈。本地方法没有方法体,但不是抽象方法,而是由native修饰的,具体实现细节在C++中的方法。
public native int hashCode();
protective native Object clone() throws CloneNotSupport Exception;

(3)程序计数器
打开编译后的Java字节码文件可以看偏移量。
系统内核控制CPU切换线程来实现多线程运行,所以每个线程都有一个程序计数器,记录不停切换的、每个线程都记录自己执行到哪儿了,切换回去的时候,那个线程可以接着执行。

(4)Java堆
存放对象实例,由线程共享,垃圾回收算法。

(5)方法区
存放Java的字节码文件,类、常量池、静态变量都在方法区。存放JIT即时编译后的常使用的代码数据。

八,回收算法
(1)引用计数法
在这里插入图片描述

(2)可达性分析算法:根可达算法
从根空间顺着引用链、找堆内存中的对象,找到的对象做标记,没有被找的对象、就是在堆中飘零的对象,全部垃圾回收掉。
根:虚拟机栈的栈桢中的符号引用、局部变量;方法区中静态属性引用的对象;方法区中常量引用的对象。
因为堆内存是有限的,内存垃圾回收时有空间碎片,对内存碎片做整合。

(3)垃圾回收算法:
标记-清除算法:标记不要的,然后清除掉。当对象较大,空间不够时再标记,再清除一遍。

标记-整理算法:标记删除不用的,把使用的对象位移成连续的空间,节省空间。

复制算法:一种用空间换时间的算法,将堆内存一分为二,一部分使用、满了就标记整理把有用的复制到另一部分空间去,复制完以后不要的就gc,原来使用的空间就腾出来了,等到下次被使用的这部分空间满了,再倒腾回去。

(4)根据对象的生命周期产生的分代算法:
青年代:对象使用次数少,需要不断gc,使用复制算法效率高。
老年代:对象使用次数多或对象占内存空间多,使用标记整理算法,节省空间。
在这里插入图片描述
九,垃圾回收器(听不懂)响应时间和吞吐量
(1)三色标记(并发标记):没有子类变黑,还有子类变灰,黑色标记垃圾回收时不管,灰色的继续标记叶子结点,remarker重新标记时,业务线全部停下来,垃圾回收标记为白色的,并发标记在remarker时可以节省时间。

(2)G1(Garbage-First):堆内存分区,每个区分代,哪个代内存不够了,可以堆内存整体兼顾所有的代、进行垃圾回收,清理出来的内存区按需求重新分代,不同代之间的引用在内存的位置没有规律导致算法比较复杂。
在这里插入图片描述

十,jvm的指令
jvm指令可以调整堆内存的大小也可以选择垃圾回收器,这些调整是会影响程序的执行效率的。想要程序频繁gc,就把堆的初始化的和最大的内存设小一点,在edit Configuration 中,选择modify options 选择Add vm options 然后Expand ,就可以输入jvm指令或打印gc日志。
-XMS20M:表示初始化的堆内存大小
-XMX20M:表示堆的最大内存
-XX:+PrintGCDetails:打印gc日志

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值