你真的了解JVM吗?
副标题[/!--empirenews.page--]
对于java程序员小白来说(没错,是我),jvm总是笼罩着一层神秘的面纱的,java是如何分配内存的,又是如何回收内存的呢?有人说内存管理是一道墙,墙里面的人想出去,墙外面的人想进去。而我们java程序员,就是硬着头皮进去的那群人... 学习的目的很简单 -----知道jvm是什么东西,它是干什么的,以及它是怎么干的 -----知其为何,何其为之 -----夸夸其谈 -----装逼 把书读薄,把知识丰满。 本文旨在记录虚拟机学习过程中的一些理解和知识点,如果有幸能帮助到你,或许可以给你提供帮助,乐意之至。 jvm分区 由java虚拟机规范规定,将java虚拟机管理的内存分为以下几个运行时的数据区域(这只是规范上面的分区,具体不同的虚拟机会有不同的实现)。 其中方法区和堆(黄色块)是 所有线程共享 的区域,虚拟机栈,本地方法栈和程序计数器这三块是 线程私有。 的区域,各个线程之间互不影响,独立存储。 区域功能
java堆 堆是内存池中最大的一块区域,也是jvm垃圾回收最主要的区域,那么我们就来梳理一下堆的知识。 对象的创建过程:前面讲到,堆是用来存放对象实例的,那么一个对象到底是如何创建又是如何放入堆中的呢? a). java中通常使用一个new关键字来创建对象,当虚拟机接收到new指令时,需要检查这个类是否已经被加载、解析和初始化,如果没有的话,需要进行相应的类加载过程。类加载的过程是分为多个阶段的,其中 初始化阶段 ,虚拟机严格规定了有且只有5种情况,属于对一个类进行 主动引用 ,必须立即堆类进行“初始化”,除此之外的所有引用都是被动引动,不会触发初始化操作。 b).虚拟机为对象分配内存,如果堆里面的内存是规整的,已经使用的内存放一边,空闲的内存放另一边,这种分配方式称为“ 指针碰撞 ”;如果内存不是规整的,那么虚拟机就要维护一个列表,记录哪些内存块是可用的,分配的时候需要从列表里面找到一块足够大的内存空间划分给对象,称为“ 空闲列表 ” c).内存分配之后,将分配到的内存空间初始化为零值 d).此时在虚拟机看来,一个新对象已经创建完成了,java执行对应的init方法,按照程序进行初始化,得到一个真正可用的对象 对象的内存布局:对象可以分为3块区域,对象头,示例数据和对齐填充,对象头又由 Mark Word 和 类型指针组成 a).Mark Word 用于存储对象自身运行时数据(HashCode、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID等) b). 类型指针 即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例 对象的定位:前面提到,java方法中对象的引用是存放在栈上的,而对象的实例是存放在堆上的。目前主流的访问方式有使用 句柄 和 直接指针 两种 a).句柄:java堆中划分出一块内存作为句柄池,reference中存储的是对象的句柄地址,句柄中含有两个地址,一个指向堆中这个对象的实例的地址,一个指向方法区中这个对象类型信息的地址 b).直接指针:reference中直接存储对象的实例地址,然后通过取到对象头中的类型指针来确定方法区中这个对象类型信息的地址。 c).比较:采用句柄的最大好处就是对象的实例地址在发生改变的时候,只需要更新句柄中指向对象实例的数据指针,不需要修改reference本身,但是可以看到相对比直接指针访问,句柄多了一次指针定位,这使得它的速度更慢。 java堆溢出:常见的就是OOM异常,导致堆溢出的原因通常有两个, 内存泄露 和 内存溢出。 a).内存泄漏:对象已经可以回收,但是却没有被回收。 那么问题来了,怎么判断一个对象是不是可以被回收或者说应该被回收呢?通常虚拟机是采用 可达性算法 来判定的,这个后面我会继续展开一下。 (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |