Java 中的垃圾回收机制

103 阅读4分钟

学习小记 JAVA第二章

最近开始看深入理解java虚拟机一书,为了防止过目即忘,再写一篇文章作为记录。本章记录java虚拟机相关内容,在内容上更倾向于个人的理解,也可以说是大白话版,欢迎指正:)

Java虚拟机运行时数据区 image.png

1. 程序计数器

java虚拟机中的多线程是通过线程轮流切换,来分配不同线程的占用处理器时间,来达到多线程执行的目的。一个处理器(对于多核处理器来说是一个内核)在同一时间只会执行来自一个线程中的指令,在不同的线程之间切换处理任务时,程序计数器可以记录该线程上次执行到哪一步了,然后继续执行下去。所以程序计数器是线程私有的。

注意:该区域是jvm中唯一一块不会出现内存溢出的区域。

2.虚拟机栈

虚拟机栈也是线程私有的,生命周期与线程相同,在每个java方法执行的同时会创建一个栈桢,用于存储局部变量表、操作数栈、动态连接、方法出口等信息,方法执行完毕后,对应的栈桢也会出栈。其中局部变量表存储了编译期间八种基本数据类型、对象的引用、返回地址(指向了一条字节码指令的地址)。这些数据类型是存储在局部变量槽中的(除了64位长度的long类型和double类型占据两个局部变量槽,其他数据类型均占用一个局部变量槽),编译期间就会指定好局部变量槽的数量(即在栈桢中分配的局部变量空间),方法运行期间不会改变局部变量的空间大小。如果线程请求的栈深度大于虚拟机所允许的深度就会报出StackOverflow错误,如果栈的深度是可以动态扩展的,当栈深度无法继续扩展(或者说剩余内存小于栈扩展请求的内存)时就会报出OutOfMemory错误。

3.本地方法栈

本地方法栈也是线程私有的,只不过是用于存储本地方法,同样也会出现StackOverflow错误与OutOfMemory错误,有些虚拟机中将它们合在了一起。

4.java堆

本篇第一个线程共享内存区域出现了!java堆随着java虚拟机启动而启动,这块区域的唯一目的就是存放对象,几乎所有的对象实例与数组都在堆上进行分配内存,虽然堆的大小是可以扩展的,并且物理上不要求内存连续,但是逻辑上应是连续的,并且数组的内存分配经常也是寻求一块连续的内存地址。堆也是java垃圾回收的地方,后面学习到的时候应该会单独开一篇文章来分享java堆的垃圾回收机制。

5.方法区

方法区也是线程共享的内存区域,用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译后的代码缓存等数据。方法区同样可以设置固定大小与动态扩展,并且还可以选择不同的垃圾回收机制(但是在方法区上进行垃圾回收效果并不理想)。

6.运行时常量池

运行时常量池是方法区的一部分,用于存储编译期生成的各种字面量与符号引用,在类加载后存放至运行时常量池中,在运行期间也可以将变量放至运行时常量池中,例如string的intern方法,调用intern方法,先去查找有无该字符串,有的话返回该字符串的引用,没有的话在运行时常量池中创建并返回该字符串的引用

7.直接内存

直接内存并不是java虚拟机运行时数据区的一部分,在jdk1.4中新增了NIO,引入了一种基于通道与缓冲区的I/O方式,特殊之处在于它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象来作为这块内存的引用进行操作,这有效的提高了部分场景中的性能,因为不需要来回在java堆和native堆中复制数据。

本篇文章到此结束,谢谢大家的观看,有错误的地方希望大家能及时指正,描述不清的地方大家也可以一起进行交流沟通。