作为开发人员,时不时回顾知识点非常有必要,不然很容易遗忘,回顾最好的方式就是用自己的语言阐述对事物的理解,所以我以后会经常使用这种方式来记录相关知识。

一、java虚拟机内存模型

完全用自己的理解描述,java虚拟机首先也是一个程序,恰当一点就是系统服务程序,它是java程序的载体,java进程其实是对操作系统应用程序进程的包装,虚拟机中的栈、堆、方法区、本地方法区、直接内存这些东西都是抽象的,是虚拟化的,java字节码它也不是机器指令,java虚拟机就是一个翻译机,将它翻译成机器码,而在底层本质上是不存在什么内存模型的,cpu执行程序都是从内存中拿到l3缓存->l2缓存->l1缓存,虚拟机这个程序和操作系统一样,将用户空间的内存划分成了多个部分。

栈------它首先是一个先入后出的数据结构,它是线程独享的一个内存空间,这个空间中存放着两个东西,一个是程序计数器、一个是栈帧,程序计数器保存方法中字节码指令的索引,栈帧中存放局部变量表、操作数栈、动态链接、返回地址,一个方法一个栈帧,方法中定义的变量都存放在局部变量表,当要计算时从局部变量表中取出放入操作数栈,计算完成重新放入局部变量表。栈默认大小1m。当递归层级过多会造成栈内存溢出异常。

堆------所有对象的实体存放在该区域,它受垃圾回收器管理,大体分为年轻代和老年代,多次gc后对象会进入老年代。

方法区----存放类的信息、常量等。

本地方法区----native方法所使用的内存区域。

直接内存----计算机上的不经过虚拟机包装的内存区域。

除了直接内存,其他都是虚拟机自身定义并管理的内存区域,也就是java进程执行的同时,虚拟机就向操作系统申请了一堆内存空间,然后划分为不同区域,让程序运行中各个部分的数据呆在合适的地方,就像生活中的二房东,房子并不是自己的,但它可以隔成很多房间,如果不隔房间就会非常乱,对于房东这个操作系统来说,它只要收租就好了,它不知道自己的房子内部结构也不需要知道,二房东只要按照我的规则把钱交给房东这个操作系统就可以了,对于租客来说,这个房子里就是一个小世界,租客只要拎包入住,各种大房东很多(各种操作系统),但是二房东把不同类型的二房东都搞定了,租客到哪只要轻装上阵,这就是java虚拟机的跨平台性。

二、java虚拟机配置参数详解

https://www.oracle.com/java/technologies/javase/vmoptions-jsp.html

三、垃圾回收器

垃圾回收主要靠可达性分析算法,也就是gc root,静态变量,运行中的成员变量、栈和本地方法栈中引用的对象、运行中的线程等可以作为gc root,被gc root 持有的强引用是不会被回收的。代码中创建的引用默认是强引用,软引用在oom时才会触发,不太常用,弱引用在gc时会触发,虚引用随时可以被回收。

四、对象分配策略

不是所有对象都分配在堆上,如果符合逃逸分析的对象就会分配在栈上,如果在方法中的对象不存在方法外的引用并且虚拟机打开了逃逸分析开关,对象就会分配在栈上,分配在栈上的对象不需要经过gc回收,方法出栈后自动消失,提升了效率。如果不符合逃逸分析,就会在堆年轻代中的eden区分配,大对象(图片数据,大数组,大字符串等)直接在老年代中分配。

堆年轻代中分为eden、from、to 三个内存区域,内存空间比例8:1:1,年轻代中和老年代中的gc是不同的,年轻代中是young gc 老年代是old gc 或者full gc ,分代的目的是为了在不同区域采用不同的垃圾回收算法,年轻代采用复制回收,老年代采用标记清除和标记整理算法。复制回收算法本质是不能回收的全部复制,其他格式化,eden区大部分对象会被gc,存活的会放入from区,age+1,放入对象的对象头信息中,触发复制回收后,from存活的会复制进入to区,from区被清理,如果from,to都满,就会进入老年代,标记整理比标记清除多做了一步整理。 不同的垃圾回收器,使用的线程数(单线程、多线程)、算法是不同的。一般垃圾回收器gc的时候会停掉用户线程,cms垃圾回收器利用了用户线程来并发标记和并发清理。cms三大缺点,cpu利用率高、浮动垃圾,内存碎片。

五、android虚拟机和虚拟机的差异

android中的虚拟机叫做dalvik虚拟机,是谷歌为移动设备定制的java虚拟机,它和传统的JVM相比,它是基于寄存器的虚拟机,当然这个寄存器并非真实的cpu寄存器,而是虚拟的寄存器,因为它符合cpu存取特征,所以它比JVM基于栈的指令的数目少很多,这样就提高了程序执行效率。在字节码文件方面,dalvik虚拟机压缩为一个独立的dex文件来优化文件读取,传统的jvm需要大量的class,每个class中常量也有可能存在重复,dalvik在字节码内容、文件数量方面都做了优化,提升了类加载效率、并且更节约内存。

dalvik虚拟机的堆区包含zygote heap和active heap ,zygote heap是进程共享的堆区,而activie heap是进程独享的。除了两个堆区还包含Card Table 来记录第一次标记的垃圾信息,还有两个Heap Bitmap 分别记录上次和这次gc的存活对象。mark stack用来gc 标记清除时来遍历存活的对象。

art虚拟机是android4.4以后发布的,art在程序安装时候有次aot 预编译,将编译的机器码存在本地,提高了运行效率,但是安装时候变长了、需要的存储空间变大了,android7.0开始art加入了即时编译器JIT,有选择的编译热点代码到机器码缓解了以上问题,dalvik是32位的,art是64位兼容32位的,art的垃圾回收器也改进了,更多的并行回收,gc暂定次数由2次减少为1次,采用了多种垃圾回收方案,art虚拟机堆区的划分也和dalvik虚拟机不一样了,它分四个堆空间,zygote space、allocation space、image space、large object space,前两个和dalvik作用一致,image space也是进程共享的。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注